Skip to content

Commit

Permalink
fix: not sync after switch network
Browse files Browse the repository at this point in the history
  • Loading branch information
classicalliu committed Oct 12, 2019
1 parent 9de23cc commit be5a014
Show file tree
Hide file tree
Showing 18 changed files with 253 additions and 95 deletions.
10 changes: 7 additions & 3 deletions packages/neuron-wallet/src/database/address/dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TransactionStatus } from 'types/cell-types'
import { OutputStatus } from 'services/tx/params'
import AddressEntity, { AddressVersion } from './entities/address'
import { getConnection } from './ormconfig'
import NodeService from 'services/node'

export interface Address {
walletId: string
Expand Down Expand Up @@ -54,7 +55,10 @@ export default class AddressDao {
// so the final balance is (liveBalance + sentBalance - pendingBalance)
// balance is the balance of the cells those who don't hold data or type script
// totalBalance means balance of all cells, including those who hold data and type script
public static updateTxCountAndBalance = async (address: string): Promise<AddressEntity[]> => {
public static updateTxCountAndBalance = async (
address: string,
url: string = NodeService.getInstance().core.rpc.node.url
): Promise<AddressEntity[]> => {
const addressEntities = await getConnection()
.getRepository(AddressEntity)
.find({
Expand All @@ -64,12 +68,12 @@ export default class AddressDao {
const txCount: number = await TransactionsService.getCountByAddressAndStatus(address, [
TransactionStatus.Pending,
TransactionStatus.Success,
])
], url)
const entities = await Promise.all(
addressEntities.map(async entity => {
const addressEntity = entity
addressEntity.txCount = txCount
const lockHashes: string[] = await LockUtils.addressToAllLockHashes(addressEntity.address)
const lockHashes: string[] = await LockUtils.addressToAllLockHashes(addressEntity.address, url)
addressEntity.liveBalance = await CellsService.getBalance(lockHashes, OutputStatus.Live, true)
addressEntity.sentBalance = await CellsService.getBalance(lockHashes, OutputStatus.Sent, true)
addressEntity.pendingBalance = await CellsService.getBalance(lockHashes, OutputStatus.Pending, true)
Expand Down
18 changes: 11 additions & 7 deletions packages/neuron-wallet/src/listeners/address.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { remote } from 'electron'
import { ReplaySubject } from 'rxjs'
import { bufferTime } from 'rxjs/operators'
import AddressesUsedSubject from 'models/subjects/addresses-used-subject'
import AddressesUsedSubject, { AddressesWithURL } from 'models/subjects/addresses-used-subject'
import AddressService from 'services/addresses'
import WalletService from 'services/wallets'
import { AccountExtendedPublicKey } from 'models/keys/key'
Expand All @@ -12,17 +12,21 @@ const addressesUsedSubject = isRenderer
: AddressesUsedSubject.getSubject()

// pipe not working directly
const bridge = new ReplaySubject<string[]>(1000)
addressesUsedSubject.subscribe((addresses: string[]) => {
bridge.next(addresses)
const bridge = new ReplaySubject<AddressesWithURL>(1000)
addressesUsedSubject.subscribe((params: AddressesWithURL) => {
bridge.next(params)
})

// update txCount when addresses used
export const register = () => {
bridge.pipe(bufferTime(1000)).subscribe(async (addressesList: string[][]) => {
const addresses = addressesList.reduce((acc, val) => acc.concat(val), [])
bridge.pipe(bufferTime(1000)).subscribe(async (addressesList: AddressesWithURL[]) => {
if (addressesList.length === 0) {
return
}
const addresses = addressesList.map(list => list.addresses).reduce((acc, val) => acc.concat(val), [])
const url: string = addressesList[addressesList.length - 1].url
const uniqueAddresses = [...new Set(addresses)]
const addrs = await AddressService.updateTxCountAndBalances(uniqueAddresses)
const addrs = await AddressService.updateTxCountAndBalances(uniqueAddresses, url)
const walletIds: string[] = addrs.map(addr => addr.walletId).filter((value, idx, a) => a.indexOf(value) === idx)
await Promise.all(
walletIds.map(async id => {
Expand Down
6 changes: 5 additions & 1 deletion packages/neuron-wallet/src/listeners/tx-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ const trackingStatus = async () => {
if (failedTxs.length) {
const blake160s = await FailedTransaction.updateFailedTxs(failedTxs.map(tx => tx.hash))
const usedAddresses = blake160s.map(blake160 => LockUtils.blake160ToAddress(blake160))
AddressesUsedSubject.getSubject().next(usedAddresses)
const { core } = nodeService
AddressesUsedSubject.getSubject().next({
addresses: usedAddresses,
url: core.rpc.node.url,
})
}

if (successTxs.length > 0) {
Expand Down
58 changes: 41 additions & 17 deletions packages/neuron-wallet/src/models/lock-utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { scriptToHash } from '@nervosnetwork/ckb-sdk-utils'
import {
scriptToHash,
AddressPrefix,
bech32Address,
AddressType,
parseAddress
} from '@nervosnetwork/ckb-sdk-utils'
import NodeService from 'services/node'
import { OutPoint, Script, ScriptHashType } from 'types/cell-types'
import env from 'env'
import ConvertTo from 'types/convert-to'
import { SystemScriptSubject } from 'models/subjects/system-script'

const { core } = NodeService.getInstance()
import Core from '@nervosnetwork/ckb-sdk-core'

export interface SystemScript {
codeHash: string
Expand All @@ -28,11 +33,15 @@ export default class LockUtils {
@subscribed
static systemScriptInfo: SystemScript | undefined

static async systemScript(): Promise<SystemScript> {
if (this.systemScriptInfo) {
static previousURL: string | undefined

static async systemScript(nodeURL: string = NodeService.getInstance().core.rpc.node.url): Promise<SystemScript> {
if (this.systemScriptInfo && nodeURL === LockUtils.previousURL) {
return this.systemScriptInfo
}

const core = new Core(nodeURL)

const systemCell = await core.loadSecp256k1Dep()
let { codeHash } = systemCell
const { outPoint, hashType } = systemCell
Expand All @@ -57,6 +66,7 @@ export default class LockUtils {
}

this.systemScriptInfo = systemScriptInfo
LockUtils.previousURL = nodeURL

return systemScriptInfo
}
Expand All @@ -80,8 +90,12 @@ export default class LockUtils {
return LockUtils.computeScriptHash(lock)
}

static async addressToLockScript(address: string, hashType: ScriptHashType = ScriptHashType.Type): Promise<Script> {
const systemScript = await this.systemScript()
static async addressToLockScript(
address: string,
hashType: ScriptHashType = ScriptHashType.Type,
nodeURL: string = NodeService.getInstance().core.rpc.node.url
): Promise<Script> {
const systemScript = await this.systemScript(nodeURL)

const lock: Script = {
codeHash: systemScript.codeHash,
Expand All @@ -91,22 +105,32 @@ export default class LockUtils {
return lock
}

static async addressToLockHash(address: string, hashType: ScriptHashType = ScriptHashType.Type): Promise<string> {
const lock: Script = await this.addressToLockScript(address, hashType)
static async addressToLockHash(
address: string,
hashType: ScriptHashType = ScriptHashType.Type,
nodeURL: string = NodeService.getInstance().core.rpc.node.url
): Promise<string> {
const lock: Script = await this.addressToLockScript(address, hashType, nodeURL)
const lockHash: string = this.lockScriptToHash(lock)

return lockHash
}

static async addressToAllLockHashes(address: string): Promise<string[]> {
const dataLockHash = await LockUtils.addressToLockHash(address)
static async addressToAllLockHashes(
address: string,
nodeURL: string = NodeService.getInstance().core.rpc.node.url
): Promise<string[]> {
const dataLockHash = await LockUtils.addressToLockHash(address, ScriptHashType.Type, nodeURL)
return [dataLockHash]
}

static async addressesToAllLockHashes(addresses: string[]): Promise<string[]> {
static async addressesToAllLockHashes(
addresses: string[],
nodeURL: string = NodeService.getInstance().core.rpc.node.url
): Promise<string[]> {
const lockHashes: string[] = (await Promise.all(
addresses.map(async addr => {
return LockUtils.addressToAllLockHashes(addr)
return LockUtils.addressToAllLockHashes(addr, nodeURL)
})
)).reduce((acc, val) => acc.concat(val), [])
return lockHashes
Expand All @@ -118,16 +142,16 @@ export default class LockUtils {
}

static blake160ToAddress(blake160: string): string {
const prefix = env.testnet ? core.utils.AddressPrefix.Testnet : core.utils.AddressPrefix.Mainnet
return core.utils.bech32Address(blake160, {
const prefix = env.testnet ? AddressPrefix.Testnet : AddressPrefix.Mainnet
return bech32Address(blake160, {
prefix,
type: core.utils.AddressType.HashIdx,
type: AddressType.HashIdx,
codeHashIndex: '0x00',
})
}

static addressToBlake160(address: string): string {
const result: string = core.utils.parseAddress(address, 'hex') as string
const result: string = parseAddress(address, 'hex') as string
const hrp: string = `0100`
let blake160: string = result.slice(hrp.length + 2, result.length)
if (!blake160.startsWith('0x')) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { ReplaySubject } from 'rxjs'

export interface AddressesWithURL {
addresses: string[]
url: string
}

// subscribe this Subject to monitor which addresses are used
export class AddressesUsedSubject {
static subject = new ReplaySubject<string[]>(100)
static subject = new ReplaySubject<AddressesWithURL>(100)

static getSubject() {
return this.subject
}

static setSubject(subject: ReplaySubject<string[]>) {
static setSubject(subject: ReplaySubject<AddressesWithURL>) {
this.subject = subject
}
}
Expand Down
8 changes: 6 additions & 2 deletions packages/neuron-wallet/src/services/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AddressDao, { Address as AddressInterface } from 'database/address/dao'
import env from 'env'
import AddressEntity, { AddressVersion } from 'database/address/entities/address'
import AddressCreatedSubject from 'models/subjects/address-created-subject'
import NodeService from './node'

const MAX_ADDRESS_COUNT = 30

Expand Down Expand Up @@ -96,10 +97,13 @@ export default class AddressService {

/* eslint no-await-in-loop: "off" */
/* eslint no-restricted-syntax: "off" */
public static updateTxCountAndBalances = async (addresses: string[]) => {
public static updateTxCountAndBalances = async (
addresses: string[],
url: string = NodeService.getInstance().core.rpc.node.url
) => {
let addrs: AddressEntity[] = []
for (const address of addresses) {
const ads = await AddressDao.updateTxCountAndBalance(address)
const ads = await AddressDao.updateTxCountAndBalance(address, url)
addrs = addrs.concat(ads)
}
return addrs
Expand Down
13 changes: 11 additions & 2 deletions packages/neuron-wallet/src/services/indexer/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ export default class IndexerQueue {

private latestCreatedBy: TxUniqueFlagCache = new TxUniqueFlagCache(100)

private url: string

constructor(url: string, lockHashInfos: LockHashInfo[], tipNumberSubject: Subject<string | undefined>) {
// this.lockHashes = lockHashes
this.lockHashInfos = lockHashInfos
this.url = url
this.indexerRPC = new IndexerRPC(url)
this.getBlocksService = new GetBlocks(url)
this.blockNumberService = new BlockNumber()
Expand Down Expand Up @@ -190,7 +193,10 @@ export default class IndexerQueue {
}
if (type === TxPointType.CreatedBy && this.latestCreatedBy.includes(txUniqueFlag)) {
const address = LockUtils.lockScriptToAddress(transaction.outputs![parseInt(txPoint.index, 16)].lock)
AddressesUsedSubject.getSubject().next([address])
AddressesUsedSubject.getSubject().next({
addresses: [address],
url: this.url,
})
return
}

Expand Down Expand Up @@ -229,7 +235,10 @@ export default class IndexerQueue {
}
}
if (address) {
AddressesUsedSubject.getSubject().next([address])
AddressesUsedSubject.getSubject().next({
addresses: [address],
url: this.url,
})
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import CheckTx from './tx'
export default class CheckAndSave {
private block: Block
private lockHashes: string[]
private url: string

constructor(block: Block, lockHashes: string[]) {
constructor(block: Block, lockHashes: string[], url: string) {
this.block = block
this.lockHashes = lockHashes
this.url = url
}

public process = async (): Promise<boolean[]> => {
const txs = this.block.transactions
let result: boolean[] = []
for (const tx of txs) {
const checkTx = new CheckTx(tx)
const checkTx = new CheckTx(tx, this.url)
const checkResult = await checkTx.checkAndSave(this.lockHashes)
result.push(checkResult)
}
Expand Down
17 changes: 14 additions & 3 deletions packages/neuron-wallet/src/services/sync/check-and-save/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ import { TransactionPersistor } from 'services/tx'
import LockUtils from 'models/lock-utils'
import CheckOutput from './output'
import { addressesUsedSubject as addressesUsedSubjectParam } from '../renderer-params'
import { AddressesWithURL } from 'models/subjects/addresses-used-subject'

export default class CheckTx {
private tx: Transaction
private addressesUsedSubject: Subject<string[]>
private addressesUsedSubject: Subject<AddressesWithURL>
private url: string

constructor(tx: Transaction, addressesUsedSubject: Subject<string[]> = addressesUsedSubjectParam) {
constructor(
tx: Transaction,
url: string,
addressesUsedSubject: Subject<AddressesWithURL> = addressesUsedSubjectParam,
) {
this.tx = tx
this.addressesUsedSubject = addressesUsedSubject

this.url = url
}

public check = async (lockHashes: string[]): Promise<string[]> => {
Expand All @@ -33,7 +41,10 @@ export default class CheckTx {
const addresses = await this.check(lockHashes)
if (addresses.length > 0) {
await TransactionPersistor.saveFetchTx(this.tx)
this.addressesUsedSubject.next(addresses)
this.addressesUsedSubject.next({
addresses,
url: this.url,
})
return true
}
return false
Expand Down
9 changes: 7 additions & 2 deletions packages/neuron-wallet/src/services/sync/get-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ export default class GetBlocks {
private retryTime: number
private retryInterval: number
private core: Core
private url: string

constructor(url: string, retryTime: number = 3, retryInterval: number = 100) {
this.retryTime = retryTime
this.retryInterval = retryInterval
this.url = url
this.core = generateCore(url)
}

Expand All @@ -39,7 +41,7 @@ export default class GetBlocks {
public checkAndSave = async (blocks: Block[], lockHashes: string[]): Promise<void> => {
for (const block of blocks) {
for (const tx of block.transactions) {
const checkTx = new CheckTx(tx)
const checkTx = new CheckTx(tx, this.url)
const addresses = await checkTx.check(lockHashes)
if (addresses.length > 0) {
for (const input of tx.inputs!) {
Expand All @@ -51,7 +53,10 @@ export default class GetBlocks {
input.capacity = previousOutput.capacity
}
await TransactionPersistor.saveFetchTx(tx)
addressesUsedSubject.next(addresses)
addressesUsedSubject.next({
addresses,
url: this.url,
})
}
}
}
Expand Down
Loading

0 comments on commit be5a014

Please sign in to comment.