def LoadCoins(self): coins = [] for coin in Coin.select(): reference = CoinReference(prev_hash=coin.TxId, prev_index=coin.Index) output = TransactionOutput(coin.AssetId, coin.Value, coin.ScriptHash) walletcoin = WalletCoin.CoinFromRef(reference, output, coin.State) coins.append(walletcoin) return coins
def LoadCoins(self): coins = {} try: for coin in Coin.select(): reference = CoinReference(prev_hash=UInt256(coin.TxId), prev_index=coin.Index) output = TransactionOutput(UInt256(coin.AssetId), Fixed8(coin.Value), UInt160(coin.ScriptHash)) walletcoin = WalletCoin.CoinFromRef(reference, output, coin.State) coins[reference] = walletcoin except Exception as e: logger.error("could not load coins %s " % e) return coins
def ProcessNewBlock(self, block): added = set() changed = set() deleted = set() try: for tx in block.FullTransactions: for index, output in enumerate(tx.outputs): state = self.CheckAddressState(output.ScriptHash) if state & AddressState.InWallet > 0: key = CoinReference(tx.Hash, index) if key in self._coins.keys(): coin = self._coins[key] coin.State |= CoinState.Confirmed changed.add(coin) else: newcoin = Coin.CoinFromRef( coin_ref=key, tx_output=output, state=CoinState.Confirmed) self._coins[key] = newcoin added.add(newcoin) if state & AddressState.WatchOnly > 0: self._coins[key].State |= CoinState.WatchOnly changed.add(self._coins[key]) for tx in block.FullTransactions: for input in tx.inputs: if input in self._coins.keys(): if self._coins[input].Output.AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): self._coins[ input].State |= CoinState.Spent | CoinState.Confirmed changed.add(self._coins[input]) else: deleted.add(self._coins[input]) del self._coins[input] for claimTx in [ tx for tx in block.Transactions if tx.Type == TransactionType.ClaimTransaction ]: for ref in claimTx.Claims: if ref in self._coins.keys(): deleted.add(self._coins[ref]) del self._coins[ref] self._current_height += 1 self.OnProcessNewBlock(block, added, changed, deleted) if len(added) + len(deleted) + len(changed) > 0: self.BalanceChanged() except Exception as e: traceback.print_stack() traceback.print_exc() print("could not process %s " % e)
def ProcessNewBlock(self, block): """ Processes a block on the blockchain. This should be done in a sequential order, ie block 4 should be only processed after block 3. Args: block: (neo.Core.Block) a block on the blockchain. """ added = set() changed = set() deleted = set() try: # go through the list of transactions in the block and enumerate # over their outputs for tx in block.FullTransactions: for index, output in enumerate(tx.outputs): # check to see if the outputs in the tx are in this wallet state = self.CheckAddressState(output.ScriptHash) if state & AddressState.InWallet > 0: # if its in the wallet, check to see if the coin exists yet key = CoinReference(tx.Hash, index) # if it exists, update it, otherwise create a new one if key in self._coins.keys(): coin = self._coins[key] coin.State |= CoinState.Confirmed changed.add(coin) else: newcoin = Coin.CoinFromRef(coin_ref=key, tx_output=output, state=CoinState.Confirmed, transaction=tx) self._coins[key] = newcoin added.add(newcoin) if state & AddressState.WatchOnly > 0: self._coins[key].State |= CoinState.WatchOnly changed.add(self._coins[key]) # now iterate over the inputs of the tx and do the same for tx in block.FullTransactions: for input in tx.inputs: if input in self._coins.keys(): if self._coins[input].Output.AssetId == Blockchain.SystemShare().Hash: coin = self._coins[input] coin.State |= CoinState.Spent | CoinState.Confirmed changed.add(coin) else: deleted.add(self._coins[input]) del self._coins[input] for claimTx in [tx for tx in block.Transactions if tx.Type == TransactionType.ClaimTransaction]: for ref in claimTx.Claims: if ref in self._coins.keys(): deleted.add(self._coins[ref]) del self._coins[ref] # update the current height of the wallet self._current_height += 1 # in the case that another wallet implementation needs to do something # with the coins that have been changed ( ie persist to db ) this # method is called self.OnProcessNewBlock(block, added, changed, deleted) # this is not necessary at the moment, but any outside process # that wants to subscribe to the balance changed event could do # so from the BalanceChanged method if len(added) + len(deleted) + len(changed) > 0: self.BalanceChanged() except Exception as e: traceback.print_stack() traceback.print_exc() logger.error("could not process %s " % e)
def SaveTransaction(self, tx): """ This method is used to after a transaction has been made by this wallet. It updates the states of the coins In the wallet to reflect the new balance, but the coins remain in a ``CoinState.UNCONFIRMED`` state until The transaction has been processed by the network. The results of these updates can be used by overriding the ``OnSaveTransaction`` method, and, for example persisting the results to a database. Args: tx (Transaction): The transaction that has been made by this wallet. Returns: bool: True is successfully processes, otherwise False if input is not in the coin list, already spent or not confirmed. """ coins = self.GetCoins() changed = [] added = [] deleted = [] found_coin = False for input in tx.inputs: coin = None for coinref in coins: test_coin = coinref.Reference if test_coin == input: coin = coinref if coin is None: return False if coin.State & CoinState.Spent > 0: return False elif coin.State & CoinState.Confirmed == 0: return False coin.State |= CoinState.Spent coin.State &= ~CoinState.Confirmed changed.append(coin) for index, output in enumerate(tx.outputs): state = self.CheckAddressState(output.ScriptHash) key = CoinReference(tx.Hash, index) if state & AddressState.InWallet > 0: newcoin = Coin.CoinFromRef(coin_ref=key, tx_output=output, state=CoinState.Unconfirmed) self._coins[key] = newcoin if state & AddressState.WatchOnly > 0: newcoin.State |= CoinState.WatchOnly added.append(newcoin) if isinstance(tx, ClaimTransaction): # do claim stuff for claim in tx.Claims: claim_coin = self._coins[claim] claim_coin.State |= CoinState.Claimed claim_coin.State &= ~CoinState.Confirmed changed.append(claim_coin) self.OnSaveTransaction(tx, added, changed, deleted) return True
def ProcessNewBlock(self, block): added = set() changed = set() deleted = set() self._lock.acquire() try: for tx in block.Transactions: for index, output in enumerate(tx.outputs): state = self.CheckAddressState(output.ScriptHash) if state > 0: key = CoinReference(tx.Hash, index) found = False for coin in self._coins: if coin.CoinRef.Equals(key): coin.State |= CoinState.Confirmed changed.add(coin.CoinRef) found = True if not found: newcoin = Coin.CoinFromRef( key, output, state=CoinState.Confirmed) self._coins.append(newcoin) added.add(newcoin.CoinRef) if state == AddressState.WatchOnly: for coin in self._coins: if coin.CoinRef.Equals(key): coin.State |= CoinState.WatchOnly changed.add(coin.CoinRef) for tx in block.Transactions: for input in tx.inputs: for coin in self._coins: if coin.CoinRef.Equals(input): if coin.TXOutput.AssetId == Blockchain.SystemShare( ).Hash(): coin.State |= CoinState.Spent | CoinState.Confirmed changed.add(coin.CoinRef) else: self._coins.remove(coin) deleted.add(coin.CoinRef) for claimTx in [ tx for tx in block.Transactions if tx.Type == TransactionType.ClaimTransaction ]: for ref in claimTx.Claims: if ref in self._coins: self._coins.remove(ref) deleted.add(ref) self._current_height += 1 self.OnProcessNewBlock(block, added, changed, deleted) if len(added) + len(deleted) + len(changed) > 0: self.BalanceChanged() except Exception as e: print("could not process: %s " % e) finally: self._lock.release()