def Contracts(self): if not self._contracts: self._contracts = Blockchain.Default().GetStates(DBPrefix.ST_Contract, ContractState) return self._contracts
def Persist(self, block): self._persisting_block = block sn = self._db.snapshot() accounts = DBCollection(self._db, sn, DBPrefix.ST_Account, AccountState) unspentcoins = DBCollection(self._db, sn, DBPrefix.ST_Coin, UnspentCoinState) spentcoins = DBCollection(self._db, sn, DBPrefix.ST_SpentCoin, SpentCoinState) assets = DBCollection(self._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(self._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(self._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(self._db, sn, DBPrefix.ST_Storage, StorageItem) amount_sysfee = self.GetSysFeeAmount( block.PrevHash) + block.TotalFees().value amount_sysfee_bytes = amount_sysfee.to_bytes(8, 'little') to_dispatch = [] with self._db.write_batch() as wb: wb.put(DBPrefix.DATA_Block + block.Hash.ToBytes(), amount_sysfee_bytes + block.Trim()) for tx in block.Transactions: wb.put(DBPrefix.DATA_Transaction + tx.Hash.ToBytes(), block.IndexBytes() + tx.ToArray()) # go through all outputs and add unspent coins to them unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed( tx.outputs) unspentcoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = accounts.GetAndChange( output.AddressBytes, AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [ coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes() ] for input in coin_refs_by_hash: uns = unspentcoins.GetAndChange( input.PrevHash.ToBytes()) uns.OrEqValueForItemAt(input.PrevIndex, CoinState.Spent) if prevTx.outputs[input.PrevIndex].AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): sc = spentcoins.GetAndChange( input.PrevHash.ToBytes(), SpentCoinState(input.PrevHash, height, [])) sc.Items.append( SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = accounts.GetAndChange( prevTx.outputs[input.PrevIndex].AddressBytes, AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance( assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [ result for result in tx.GetTransactionResults() if result.Amount.value < 0 ] for result in txresults: asset = assets.GetAndChange(result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = spentcoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) spentcoins.GetAndChange(input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: newvalidator = ValidatorState(pub_key=tx.PublicKey) validators.GetAndChange(tx.PublicKey.ToBytes(), newvalidator) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: contract = ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), contract) elif tx.Type == TransactionType.InvocationTransaction: script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, wb) engine = ApplicationEngine( trigger_type=TriggerType.Application, container=tx, table=script_table, service=service, gas=tx.Gas, testMode=False) engine.LoadScript(tx.Script, False) try: success = engine.Execute() service.ExecutionCompleted(engine, success) except Exception as e: service.ExecutionCompleted(engine, False, e) to_dispatch = to_dispatch + service.events_to_dispatch else: if tx.Type != b'\x00' and tx.Type != 128: logger.info("TX Not Found %s " % tx.Type) # do save all the accounts, unspent, coins, validators, assets, etc # now sawe the current sys block # filter out accounts to delete then commit for key, account in accounts.Current.items(): if not account.IsFrozen and len( account.Votes) == 0 and account.AllBalancesZeroOrLess( ): accounts.Remove(key) accounts.Commit(wb) # filte out unspent coins to delete then commit for key, unspent in unspentcoins.Current.items(): if unspent.IsAllSpent: unspentcoins.Remove(key) unspentcoins.Commit(wb) # filter out spent coins to delete then commit to db for key, spent in spentcoins.Current.items(): if len(spent.Items) == 0: spentcoins.Remove(key) spentcoins.Commit(wb) # commit validators validators.Commit(wb) # commit assets assets.Commit(wb) # commit contracts contracts.Commit(wb) # commit storages ( not implemented ) storages.Commit(wb) sn.close() wb.put(DBPrefix.SYS_CurrentBlock, block.Hash.ToBytes() + block.IndexBytes()) self._current_block_height = block.Index self._persisting_block = None for event in to_dispatch: events.emit(event.event_type, event)
def TestInvokeContract(wallet, args, withdrawal_tx=None, parse_params=True, from_addr=None, min_fee=DEFAULT_MIN_FEE): BC = GetBlockchain() contract = BC.GetContract(args[0]) if contract: verbose = False if 'verbose' in args: descripe_contract(contract) verbose = True args.remove('verbose') # params = args[1:] if len(args) > 1 else [] if len(params) > 0 and params[0] == 'describe': return params, neo_to_attach, gas_to_attach = get_asset_attachments(params) params.reverse() sb = ScriptBuilder() for p in params: if parse_params: item = parse_param(p, wallet) else: item = p if type(item) is list: item.reverse() listlength = len(item) for listitem in item: sb.push(listitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(item) sb.EmitAppCall(contract.Code.ScriptHash().Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract.Code.ScriptHash()) outputs.append(output) return test_invoke(out, wallet, outputs, withdrawal_tx, from_addr, min_fee) else: print("Contract %s not found" % args[0]) return None, None, None, None
def main(): parser = argparse.ArgumentParser() parser.add_argument("-m", "--mainnet", action="store_true", default=False, help="Use MainNet instead of the default TestNet") parser.add_argument("-p", "--privnet", action="store_true", default=False, help="Use PrivNet instead of the default TestNet") parser.add_argument("-c", "--config", action="store", help="Use a specific config file") parser.add_argument( "-t", "--set-default-theme", dest="theme", choices=["dark", "light"], help= "Set the default theme to be loaded from the config file. Default: 'dark'" ) parser.add_argument( '--version', action='version', version='neo-python v{version}'.format(version=__version__)) args = parser.parse_args() if args.config and (args.mainnet or args.privnet): print( "Cannot use both --config and --mainnet/--privnet arguments, please use only one." ) exit(1) if args.mainnet and args.privnet: print("Cannot use both --mainnet and --privnet arguments") exit(1) # Setup depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() elif args.privnet: settings.setup_privnet() if args.theme: preferences.set_theme(args.theme) # Instantiate the blockchain and subscribe to notifications blockchain = LevelDBBlockchain(settings.LEVELDB_PATH) Blockchain.RegisterBlockchain(blockchain) # Start the prompt interface cli = PromptInterface() # Run reactor.suggestThreadPoolSize(15) reactor.callInThread(cli.run) NodeLeader.Instance().Start() reactor.run()
async def StartProcol(self): message = Message( "version", VersionPayload(self._local_node._port, self._local_node._nonce, self._local_node.UserAgent)) result_future = await asyncio.wait_for(self.SendMessageAsync(message), 60.0) if not result_future: return message_rec = await asyncio.wait_for( self.ReceiveMessageAsync(self.HalfMinute), 60.0) if message_rec is None: return try: if message_rec.Command != 'version': self.__log.debug("command is not version...., disconnecting") self.Disconnect(True) return except Exception as e: print("could not receive message command %s " % e) return try: self.Version = IOHelper.AsSerializableWithType( message_rec.Payload, "neo.Network.Payloads.VersionPayload.VersionPayload") self.__log.debug("CURRENT VERSION START HEIGHT: %s " % self.Version.StartHeight) except Exception as e: print("exception getting version: %s " % e) self.Disconnect(e) return if self.Version.Nonce != self._local_node._nonce: self.__log.debug("unequal nonces: %s %s " % (self.Version.Nonce, self._local_node._nonce)) # self.Disconnect(True) # return #lock localnode connected peers # if (localNode.connectedPeers.Where(p= > p != this).Any(p= > p.RemoteEndpoint.Address.Equals( # RemoteEndpoint.Address) & & p.Version?.Nonce == Version.Nonce)) # { # Disconnect(false); # return; # } #endlock if self.ListenerEndpoint is not None: if self.ListenerEndpoint.Port != self.Version.Port: self.Disconnect(True) return elif self.Version.Port > 0: self.ListenerEndpoint = IPEndpoint(self.RemoteEndpoint.Address, self.Version.Port) verack = await asyncio.wait_for( self.SendMessageAsync(Message("verack")), 60.0) if verack is None or verack is False: return self.__log.debug("VERACK") vmessage = await asyncio.wait_for( self.ReceiveMessageAsync(self.HalfMinute), 60.0) if vmessage is None or vmessage.Command != "verack": self.Disconnect(True) return self.__log.debug( "Header height, start height: %s %s" % (Blockchain.Default().HeaderHeight(), self.Version.StartHeight)) if Blockchain.Default().HeaderHeight() < self.Version.StartHeight: self.__log.debug( "XXXXXXXXXXXX ENCQUING GET HEADERS MESSSSAAGGEGEE %s " % Blockchain.Default().CurrentHeaderHash()) self.EnqueueMessage( "getheaders", GetBlocksPayload(Blockchain.Default().CurrentHeaderHash()), True) sendloop = asyncio.run_coroutine_threadsafe(self.StartSendLoop(), asyncio.get_event_loop()) while self._disposed == 0: if Blockchain.Default() is not None: if len(self._missions) == 0 and Blockchain.Default().Height( ) < self.Version.StartHeight: self.__log.debug("GET BLOCKS MESSAGE %s" % Blockchain.Default().CurrentBlockHash()) self.EnqueueMessage( "getblocks", GetBlocksPayload( Blockchain.Default().CurrentBlockHash()), True) timeout = self.HalfHour if len( self._missions) == 0 else self.OneMinute receive_message_future = await asyncio.wait_for( self.ReceiveMessageAsync(timeout), 10) if not receive_message_future: print("no message future!: ") break try: self.OnMessageReceived(receive_message_future) except Exception as e: print("could not receive message: %s " % e) self.Disconnect(True) break
def test_invoke(script, wallet, outputs, withdrawal_tx=None): # print("invoke script %s " % script) bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, sn, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, sn, DBPrefix.ST_Storage, StorageItem) # if we are using a withdrawal tx, don't recreate the invocation tx # also, we don't want to reset the inputs / outputs # since those were already calculated if withdrawal_tx is not None: tx = withdrawal_tx else: tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) if len(outputs) < 1: contract = wallet.GetDefaultContract() tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash( contract.Script).Data) ] # same as above. we don't want to re-make the transaction if it is a withdrawal tx if withdrawal_tx is not None: wallet_tx = tx else: wallet_tx = wallet.MakeTransaction(tx=tx) if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() engine = ApplicationEngine(trigger_type=TriggerType.Application, container=wallet_tx, table=script_table, service=service, gas=wallet_tx.Gas, testMode=True) engine.LoadScript(wallet_tx.Script, False) try: # drum roll? success = engine.Execute() if success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed.value = int(consumed.value) net_fee = None tx_gas = None if consumed < Fixed8.FromDecimal(10.0): net_fee = Fixed8.FromDecimal(.001) tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() # set the amount of gas the tx will need wallet_tx.Gas = tx_gas # reset the wallet outputs wallet_tx.outputs = outputs wallet_tx.Attributes = [] return wallet_tx, net_fee, engine.EvaluationStack.Items, engine.ops_processed else: print("error executing contract.....") return None, None, None, None except Exception as e: print("COULD NOT EXECUTE %s " % e) return None, None, None, None
def quit(self): print('Shutting down. This may take a bit...') self.go_on = False Blockchain.Default().Dispose() reactor.stop() NodeLeader.Instance().Shutdown()
def runPrompt(self): dbloop = task.LoopingCall(Blockchain.Default().PersistBlocks) dbloop.start(.1) Blockchain.Default().PersistBlocks() self.createWallet() self.autoDeploy() print("\n") # self.withdrawFunds(self.Wallet) # self.exit() while self.go_on: try: result = prompt( "neoFund> ", completer=self.get_completer(), history=self.history, get_bottom_toolbar_tokens=self.get_bottom_toolbar, style=self.token_style, refresh_interval=.5) except EOFError: # Control-D pressed: quit return self.quit() except KeyboardInterrupt: # Control-C pressed: do nothing continue try: command, arguments = self.parse_result(result) if command is not None and len(command) > 0: # command = command.lower() print(command) if command == 'quit' or command == 'exit': self.quit() elif command == 'help': self.help() elif command == 'tx': self.show_tx(arguments) elif command == 'wallet': self.show_wallet(arguments) elif command == 'invokeDeploy': self.invokeDeploy() elif command == 'createFund': self.createFund(self.Wallet, test_fund, 'neo', 'withdrawal_SH', 100, 9999) elif command == 'getFundParameter': self.getFundParameter(self.Wallet, test_fund, 'fundBalance') elif command == 'depositFunds': self.depositFunds(self.Wallet, test_fund, 'neo', 5, args=arguments) elif command == 'withdrawFunds': self.withdrawFunds(self.Wallet, 1, args=arguments) elif command == 'withdrawRequestFunds': self.withdrawRequestFunds(self.Wallet, test_fund, 1, args=arguments) elif command == 'withdrawRequestReset': self.withdrawRequestReset(self.Wallet) elif command == 'importContract': self.importContract() elif command == 'send_test_funds': self.send_test_funds() elif command == 'deleteAddr': DeleteAddress(self, self.Wallet, arguments[0]) elif command == 'isRefundActive': self.isRefundActive(test_fund) elif command is None: print('please specify a command') else: print("command %s not found" % command) except Exception as e: print("could not execute command: %s " % e) traceback.print_stack() traceback.print_exc()
def ExecutionCompleted(self, engine, success, error=None): height = Blockchain.Default().Height tx_hash = None if engine.ScriptContainer: tx_hash = engine.ScriptContainer.Hash if not tx_hash: tx_hash = UInt256(data=bytearray(32)) entry_script = None try: # get the first script that was executed # this is usually the script that sets up the script to be executed entry_script = UInt160(data=engine.ExecutedScriptHashes[0]) # ExecutedScriptHashes[1] will usually be the first contract executed if len(engine.ExecutedScriptHashes) > 1: entry_script = UInt160(data=engine.ExecutedScriptHashes[1]) except Exception as e: logger.error("Could not get entry script: %s " % e) payload = [] for item in engine.EvaluationStack.Items: payload_item = stack_item_to_py(item) payload.append(payload_item) if success: # dispatch all notify events, along with the success of the contract execution for notify_event_args in self.notifications: self.events_to_dispatch.append( NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, notify_event_args.State, notify_event_args.ScriptHash, height, tx_hash, success, engine.testMode)) if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_FAIL, [payload, error, engine._VMState], entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_FAIL, [payload, error, engine._VMState], entry_script, height, tx_hash, success, engine.testMode)) self.notifications = []
def MonkeyPatchPersist(self, block, snapshot=None): if snapshot is None: snapshot = self._db.createSnapshot() snapshot.PersistingBlock = block amount_sysfee = self.GetSysFeeAmount( block.PrevHash) + (block.TotalFees().value / Fixed8.D) amount_sysfee_bytes = struct.pack("<d", amount_sysfee) with self._db.getBatch() as wb: for tx in block.Transactions: unspentcoinstate = UnspentCoinState.FromTXOutputsConfirmed( tx.outputs) snapshot.UnspentCoins.Add(tx.Hash.ToBytes(), unspentcoinstate) # go through all the accounts in the tx outputs for output in tx.outputs: account = snapshot.Accounts.GetAndChange( output.AddressBytes, lambda: AccountState(output.ScriptHash)) if account.HasBalance(output.AssetId): account.AddToBalance(output.AssetId, output.Value) else: account.SetBalanceFor(output.AssetId, output.Value) # go through all tx inputs unique_tx_input_hashes = [] for input in tx.inputs: if input.PrevHash not in unique_tx_input_hashes: unique_tx_input_hashes.append(input.PrevHash) for txhash in unique_tx_input_hashes: prevTx, height = self.GetTransaction(txhash.ToBytes()) coin_refs_by_hash = [ coinref for coinref in tx.inputs if coinref.PrevHash.ToBytes() == txhash.ToBytes() ] for input in coin_refs_by_hash: snapshot.UnspentCoins.GetAndChange( input.PrevHash.ToBytes()).Items[ input.PrevIndex] |= CoinState.Spent if prevTx.outputs[input.PrevIndex].AssetId.ToBytes( ) == Blockchain.SystemShare().Hash.ToBytes(): sc = snapshot.SpentCoins.GetAndChange( input.PrevHash.ToBytes(), lambda: SpentCoinState(input.PrevHash, height, [])) sc.Items.append( SpentCoinItem(input.PrevIndex, block.Index)) output = prevTx.outputs[input.PrevIndex] acct = snapshot.Accounts.GetAndChange( prevTx.outputs[input.PrevIndex].AddressBytes, lambda: AccountState(output.ScriptHash)) assetid = prevTx.outputs[input.PrevIndex].AssetId acct.SubtractFromBalance( assetid, prevTx.outputs[input.PrevIndex].Value) # do a whole lotta stuff with tx here... if tx.Type == TransactionType.RegisterTransaction: asset = AssetState(tx.Hash, tx.AssetType, tx.Name, tx.Amount, Fixed8(0), tx.Precision, Fixed8(0), Fixed8(0), UInt160(data=bytearray(20)), tx.Owner, tx.Admin, tx.Admin, block.Index + 2 * 2000000, False) snapshot.Assets.Add(tx.Hash.ToBytes(), asset) elif tx.Type == TransactionType.IssueTransaction: txresults = [ result for result in tx.GetTransactionResults() if result.Amount.value < 0 ] for result in txresults: asset = snapshot.Assets.GetAndChange( result.AssetId.ToBytes()) asset.Available = asset.Available - result.Amount elif tx.Type == TransactionType.ClaimTransaction: for input in tx.Claims: sc = snapshot.SpentCoins.TryGet(input.PrevHash.ToBytes()) if sc and sc.HasIndex(input.PrevIndex): sc.DeleteIndex(input.PrevIndex) snapshot.SpentCoins.GetAndChange( input.PrevHash.ToBytes()) elif tx.Type == TransactionType.EnrollmentTransaction: snapshot.Validators.GetAndChange( tx.PublicKey.ToBytes(), lambda: ValidatorState(pub_key=tx.PublicKey)) # logger.info("VALIDATOR %s " % validator.ToJson()) elif tx.Type == TransactionType.StateTransaction: # @TODO Implement persistence for State Descriptors pass elif tx.Type == TransactionType.PublishTransaction: def create_contract_state(): return ContractState(tx.Code, tx.NeedStorage, tx.Name, tx.CodeVersion, tx.Author, tx.Email, tx.Description) snapshot.Contracts.GetAndChange(tx.Code.ScriptHash().ToBytes(), create_contract_state) elif tx.Type == TransactionType.InvocationTransaction: return ApplicationEngine.Run(TriggerType.Application, tx, snapshot.Clone(), tx.Gas, True, wb)
def AskForMoreHeaders(self): # self.Log("asking for more headers...") get_headers_message = Message( "getheaders", GetBlocksPayload(hash_start=[BC.Default().CurrentHeaderHash])) self.SendSerializedMessage(get_headers_message)
def setUpClass(cls): Blockchain.DeregisterBlockchain() super(BlockchainFixtureTestCase, cls).setUpClass() # for some reason during testing asyncio.get_event_loop() fails and does not create a new one if needed. This is the workaround try: loop = asyncio.get_running_loop() except RuntimeError: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) nodemgr = NodeManager() nodemgr.reset_for_test() # setup Blockchain DB if not os.path.exists(cls.FIXTURE_FILENAME): logger.info( "downloading fixture block database from %s. this may take a while" % cls.FIXTURE_REMOTE_LOC) response = requests.get(cls.FIXTURE_REMOTE_LOC, stream=True) response.raise_for_status() os.makedirs(os.path.dirname(cls.FIXTURE_FILENAME), exist_ok=True) with open(cls.FIXTURE_FILENAME, 'wb+') as handle: for block in response.iter_content(1024): handle.write(block) try: tar = tarfile.open(cls.FIXTURE_FILENAME) tar.extractall(path=settings.DATA_DIR_PATH) tar.close() except Exception as e: raise Exception( "Could not extract tar file - %s. You may want need to remove the fixtures file %s manually to fix this." % (e, cls.FIXTURE_FILENAME)) if not os.path.exists(cls.leveldb_testpath()): raise Exception("Error downloading fixtures at %s" % cls.leveldb_testpath()) settings.setup_unittest_net() cls._blockchain = Blockchain( getBlockchainDB(path=cls.leveldb_testpath()), skip_version_check=True) cls._blockchain.UT = True Blockchain.RegisterBlockchain(cls._blockchain) # setup Notification DB if not os.path.exists(cls.N_FIXTURE_FILENAME): logger.info( "downloading fixture notification database from %s. this may take a while" % cls.N_FIXTURE_REMOTE_LOC) response = requests.get(cls.N_FIXTURE_REMOTE_LOC, stream=True) response.raise_for_status() with open(cls.N_FIXTURE_FILENAME, 'wb+') as handle: for block in response.iter_content(1024): handle.write(block) try: tar = tarfile.open(cls.N_FIXTURE_FILENAME) tar.extractall(path=settings.DATA_DIR_PATH) tar.close() except Exception as e: raise Exception( "Could not extract tar file - %s. You may want need to remove the fixtures file %s manually to fix this." % (e, cls.N_FIXTURE_FILENAME)) if not os.path.exists(cls.N_NOTIFICATION_DB_NAME): raise Exception("Error downloading fixtures at %s" % cls.N_NOTIFICATION_DB_NAME) settings.NOTIFICATION_DB_PATH = cls.N_NOTIFICATION_DB_NAME ndb = NotificationDB.instance() ndb.start()
async def setup_and_start(loop): parser = argparse.ArgumentParser() # Network options group_network_container = parser.add_argument_group( title="Network options") group_network = group_network_container.add_mutually_exclusive_group( required=True) group_network.add_argument("--mainnet", action="store_true", default=False, help="Use MainNet") group_network.add_argument("--testnet", action="store_true", default=False, help="Use TestNet") group_network.add_argument("--privnet", action="store_true", default=False, help="Use PrivNet") group_network.add_argument("--coznet", action="store_true", default=False, help="Use CozNet") group_network.add_argument("--config", action="store", help="Use a specific config file") # Ports for RPC and REST api group_modes = parser.add_argument_group(title="Mode(s)") group_modes.add_argument( "--port-rpc", type=int, help="port to use for the json-rpc api (eg. 10332)") group_modes.add_argument("--port-rest", type=int, help="port to use for the rest api (eg. 80)") # Advanced logging setup group_logging = parser.add_argument_group(title="Logging options") group_logging.add_argument("--logfile", action="store", type=str, help="Logfile") group_logging.add_argument( "--syslog", action="store_true", help= "Log to syslog instead of to log file ('user' is the default facility)" ) group_logging.add_argument( "--syslog-local", action="store", type=int, choices=range(0, 7 + 1), metavar="[0-7]", help= "Log to a local syslog facility instead of 'user'. Value must be between 0 and 7 (e.g. 0 for 'local0')." ) group_logging.add_argument("--disable-stderr", action="store_true", help="Disable stderr logger") # Where to store stuff parser.add_argument("--datadir", action="store", help="Absolute path to use for database directories") # peers parser.add_argument("--minpeers", action="store", type=int, choices=range(1, 10 + 1), metavar="[1-10]", help="Min peers to use for P2P Joining") parser.add_argument("--maxpeers", action="store", type=int, choices=range(1, 10 + 1), metavar="[1-10]", help="Max peers to use for P2P Joining") # If a wallet should be opened parser.add_argument( "--wallet", action="store", help= "Open wallet. Will allow you to use methods that require an open wallet" ) # host parser.add_argument("--host", action="store", type=str, help="Hostname ( for example 127.0.0.1)", default="0.0.0.0") # Now parse args = parser.parse_args() # print(args) if not args.port_rpc and not args.port_rest: print("Error: specify at least one of --port-rpc / --port-rest") parser.print_help() raise SystemExit if args.port_rpc == args.port_rest: print("Error: --port-rpc and --port-rest cannot be the same") parser.print_help() raise SystemExit if args.logfile and (args.syslog or args.syslog_local): print("Error: Cannot only use logfile or syslog at once") parser.print_help() raise SystemExit # Setting the datadir must come before setting the network, else the wrong path is checked at net setup. if args.datadir: settings.set_data_dir(args.datadir) # Network configuration depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() elif args.testnet: settings.setup_testnet() elif args.privnet: settings.setup_privnet() elif args.coznet: settings.setup_coznet() def set_min_peers(num_peers) -> bool: try: settings.set_min_peers(num_peers) print("Minpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for minpeers") return False def set_max_peers(num_peers) -> bool: try: settings.set_max_peers(num_peers) print("Maxpeers set to ", num_peers) return True except ValueError: print("Please supply a positive integer for maxpeers") return False minpeers = args.minpeers maxpeers = args.maxpeers if minpeers and maxpeers: if minpeers > maxpeers: print("minpeers setting cannot be bigger than maxpeers setting") return if not set_min_peers(minpeers) or not set_max_peers(maxpeers): return elif minpeers: if not set_min_peers(minpeers): return if minpeers > settings.CONNECTED_PEER_MAX: if not set_max_peers(minpeers): return elif maxpeers: if not set_max_peers(maxpeers): return if maxpeers < settings.CONNECTED_PEER_MIN: if not set_min_peers(maxpeers): return if args.syslog or args.syslog_local is not None: # Setup the syslog facility if args.syslog_local is not None: print("Logging to syslog local%s facility" % args.syslog_local) syslog_facility = SysLogHandler.LOG_LOCAL0 + args.syslog_local else: print("Logging to syslog user facility") syslog_facility = SysLogHandler.LOG_USER # Setup logzero to only use the syslog handler logzero.syslog(facility=syslog_facility) else: # Setup file logging if args.logfile: logfile = os.path.abspath(args.logfile) if args.disable_stderr: print("Logging to logfile: %s" % logfile) else: print("Logging to stderr and logfile: %s" % logfile) logzero.logfile(logfile, maxBytes=LOGFILE_MAX_BYTES, backupCount=LOGFILE_BACKUP_COUNT, disableStderrLogger=args.disable_stderr) else: print("Logging to stdout and stderr") if args.wallet: if not os.path.exists(args.wallet): print("Wallet file not found") return passwd = os.environ.get('NEO_PYTHON_JSONRPC_WALLET_PASSWORD', None) if not passwd: try: passwd = prompt("[password]> ", is_password=True) except KeyboardInterrupt: print("Wallet opening cancelled") return password_key = to_aes_key(passwd) try: wallet = UserWallet.Open(args.wallet, password_key) asyncio.create_task( wallet.sync_wallet(start_block=wallet._current_height)) except Exception as e: print(f"Could not open wallet {e}") return else: wallet = None # Disable logging smart contract events settings.set_log_smart_contract_events(False) # Write a PID file to easily quit the service write_pid_file() # Instantiate the blockchain and subscribe to notifications blockchain = Blockchain(getBlockchainDB()) Blockchain.RegisterBlockchain(blockchain) p2p = NetworkService() p2p_task = loop.create_task(p2p.start()) loop.create_task(custom_background_code()) NotificationDB.instance().start() if args.port_rpc: logger.info("Starting json-rpc api server on http://%s:%s" % (args.host, args.port_rpc)) try: rpc_class = load_class_from_path(settings.RPC_SERVER) except ValueError as err: logger.error(err) sys.exit() api_server_rpc = rpc_class(wallet=wallet) runner = web.AppRunner(api_server_rpc.app) await runner.setup() site = web.TCPSite(runner, args.host, args.port_rpc) await site.start() if args.port_rest: logger.info("Starting REST api server on http://%s:%s" % (args.host, args.port_rest)) try: rest_api = load_class_from_path(settings.REST_SERVER) except ValueError as err: logger.error(err) sys.exit() api_server_rest = rest_api() runner = web.AppRunner(api_server_rest.app) await runner.setup() site = web.TCPSite(runner, args.host, args.port_rpc) await site.start() return wallet
def Storages(self): if not self._storages: self._storages = Blockchain.Default().GetStates(DBPrefix.ST_Storage, StorageItem) return self._storages
def NEO(self): return Blockchain.Default().SystemShare().Hash
def ToJson(self, verbose=False): assets = self.GetCoinAssets() tokens = list(self._tokens.values()) assets = assets + tokens if Blockchain.Default().Height == 0: percent_synced = 0 else: percent_synced = int(100 * self._current_height / Blockchain.Default().Height) jsn = {} jsn['path'] = self._path addresses = [] has_watch_addr = False for addr in Address.select(): # print("Script hash %s %s" % (addr.ScriptHash, type(addr.ScriptHash))) addr_str = Crypto.ToAddress(UInt160(data=addr.ScriptHash)) acct = Blockchain.Default().GetAccountState(addr_str) token_balances = self.TokenBalancesForAddress(addr_str) if acct: json = acct.ToJson() json['is_watch_only'] = addr.IsWatchOnly addresses.append(json) if token_balances: json['tokens'] = token_balances if addr.IsWatchOnly: has_watch_addr = True else: addresses.append(addr_str) balances = [] watch_balances = [] for asset in assets: if type(asset) is UInt256: bc_asset = Blockchain.Default().GetAssetState(asset.ToBytes()) total = self.GetBalance(asset).value / Fixed8.D watch_total = self.GetBalance(asset, bool(CoinState.WatchOnly)).value / Fixed8.D balances.append("[%s]: %s " % (bc_asset.GetName(), total)) watch_balances.append("[%s]: %s " % (bc_asset.GetName(), watch_total)) elif type(asset) is WalletNEP5Token: balances.append("[%s]: %s " % (asset.symbol, self.GetBalance(asset))) watch_balances.append("[%s]: %s " % (asset.symbol, self.GetBalance(asset, True))) tokens = [] for t in self._tokens.values(): tokens.append(t.ToJson()) jsn['addresses'] = addresses jsn['height'] = self._current_height jsn['percent_synced'] = percent_synced jsn['synced_balances'] = balances if has_watch_addr: jsn['synced_watch_only_balances'] = watch_balances jsn['public_keys'] = self.PubKeys() jsn['tokens'] = tokens jsn['claims'] = { 'available': self.GetAvailableClaimTotal().ToString(), 'unavailable': self.GetUnavailableBonus().ToString() } if verbose: jsn['coins'] = [coin.ToJson() for coin in self.FindUnspentCoins()] jsn['transactions'] = [tx.ToJson() for tx in self.GetTransactions()] return jsn
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()
break i += 1 if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-o", "--output", action="store", help="Filename of wallet that will be created (default: %s)" % WALLET_PATH, default=WALLET_PATH) parser.add_argument("-p", "--password", action="store", help="Wallet password (default: %s)" % WALLET_PWD, default=WALLET_PWD) parser.add_argument("-t", "--time", action="store", help="Minutes to wait for the MFF to generate GAS (default: %s)" % MINUTES_TO_WAIT_UNTIL_GAS_CLAIM, default=MINUTES_TO_WAIT_UNTIL_GAS_CLAIM) parser.add_argument("-w", "--save-privnet-wif", action="store", help="Filename to store created privnet wif key") args = parser.parse_args() if os.path.isfile(args.output): print("Error: Wallet file %s already exists" % args.output) exit(1) settings.setup_privnet() print("Blockchain DB path:", settings.chain_leveldb_path) if os.path.exists(settings.chain_leveldb_path): print("Warning: Chain database already exists. If this is from a previous private network, you need to delete %s" % settings.chain_leveldb_path) blockchain = LevelDBBlockchain(settings.chain_leveldb_path) Blockchain.RegisterBlockchain(blockchain) reactor.suggestThreadPoolSize(15) NodeLeader.Instance().Start() pc = PrivnetClaimall(args.output, args.password, args.time, args.save_privnet_wif) reactor.callInThread(pc.run) reactor.run()
def test_deploy_and_invoke(deploy_script, invoke_args, wallet): bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, sn, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, sn, DBPrefix.ST_Storage, StorageItem) dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) dtx = wallet.MakeTransaction(tx=dtx) context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() dtx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script)) ] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=dtx, table=script_table, service=service, gas=dtx.Gas, testMode=True) engine.LoadScript(dtx.Script, False) # first we will execute the test deploy # then right after, we execute the test invoke try: d_success = engine.Execute() if d_success: items = engine.EvaluationStack.Items contract_state = None for i in items: if type(i) is ContractState: contract_state = i break elif type(i) is InteropInterface: item = i.GetInterface('neo.whatever') if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() invoke_args, neo_to_attach, gas_to_attach = get_asset_attachments( invoke_args) invoke_args.reverse() sb = ScriptBuilder() # print("neo, gas %s %s " % (neo_to_attach,gas_to_attach.ToString())) sb = ScriptBuilder() for p in invoke_args: item = parse_param(p) if type(item) is list: item.reverse() listlength = len(item) for listitem in item: sb.push(listitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(item) sb.EmitAppCall(shash.Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract_state.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract_state.Code.ScriptHash()) outputs.append(output) itx = InvocationTransaction() itx.Version = 1 itx.outputs = outputs itx.inputs = [] itx.scripts = [] itx.Attributes = [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1: contract = wallet.GetDefaultContract() itx.Attributes = [ TransactionAttribute( usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script).Data) ] itx = wallet.MakeTransaction(tx=itx) context = ContractParametersContext(itx) wallet.Sign(context) itx.scripts = context.GetScripts() # print("tx: %s " % json.dumps(itx.ToJson(), indent=4)) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=itx, table=script_table, service=service, gas=itx.Gas, testMode=True) engine.LoadScript(itx.Script, False) i_success = engine.Execute() if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed.value = int(consumed.value) if consumed < Fixed8.One(): consumed = Fixed8.FromDecimal(.001) total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultsForCode(contract_state.Code) return itx, result, total_ops else: print("error executing invoke contract...") else: print("error executing deploy contract.....") except Exception as e: print("COULD NOT EXECUTE %s " % e) traceback.print_stack() traceback.print_exc() return None, [], 0
def main(): parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument("-m", "--mainnet", action="store_true", default=False, help="Use MainNet instead of the default TestNet") group.add_argument("-p", "--privnet", action="store_true", default=False, help="Use PrivNet instead of the default TestNet") group.add_argument( "--coznet", action="store_true", default=False, help="Use the CoZ network instead of the default TestNet") group.add_argument("-c", "--config", action="store", help="Use a specific config file") parser.add_argument( "-t", "--set-default-theme", dest="theme", choices=["dark", "light"], help= "Set the default theme to be loaded from the config file. Default: 'dark'" ) parser.add_argument( "--version", action="version", version="neo-python v{version}".format(version=__version__)) args = parser.parse_args() # Setup depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() elif args.privnet: settings.setup_privnet() elif args.coznet: settings.setup_coznet() if args.theme: preferences.set_theme(args.theme) # Instantiate the blockchain and subscribe to notifications blockchain = LevelDBBlockchain(settings.LEVELDB_PATH) Blockchain.RegisterBlockchain(blockchain) # Try to set up a notification db if NotificationDB.instance(): NotificationDB.instance().start() # Start the prompt interface cli = PromptInterface() # Run things reactor.suggestThreadPoolSize(15) reactor.callInThread(cli.run) NodeLeader.Instance().Start() # reactor.run() is blocking, until `quit()` is called which stops the reactor. reactor.run() # After the reactor is stopped, gracefully shutdown the database. NotificationDB.close() Blockchain.Default().Dispose() NodeLeader.Instance().Shutdown()
def run(self): dbloop = task.LoopingCall(Blockchain.Default().PersistBlocks) dbloop.start(.1) Blockchain.Default().PersistBlocks() tokens = [(Token.Neo, 'NEO'), (Token.Default, ' cli. Type '), (Token.Command, "'help' "), (Token.Default, 'to get started')] print_tokens(tokens, self.token_style) print("\n") while self.go_on: try: result = prompt( "neo> ", completer=self.get_completer(), history=self.history, get_bottom_toolbar_tokens=self.get_bottom_toolbar, style=self.token_style, refresh_interval=3) except EOFError: # Control-D pressed: quit return self.quit() except KeyboardInterrupt: # Control-C pressed: do nothing continue try: command, arguments = self.parse_result(result) if command is not None and len(command) > 0: command = command.lower() if command == 'quit' or command == 'exit': self.quit() elif command == 'help': self.help() elif command == 'create': self.do_create(arguments) elif command == 'open': self.do_open(arguments) elif command == 'build': self.do_build(arguments) elif command == 'load_run': self.do_load_n_run(arguments) elif command == 'import': self.do_import(arguments) elif command == 'export': self.do_export(arguments) elif command == 'wallet': self.show_wallet(arguments) elif command == 'send': self.do_send(arguments) elif command == 'sign': self.do_sign(arguments) elif command == 'block': self.show_block(arguments) elif command == 'tx': self.show_tx(arguments) elif command == 'header': self.show_header(arguments) elif command == 'account': self.show_account_state(arguments) elif command == 'asset': self.show_asset_state(arguments) elif command == 'contract': self.show_contract_state(arguments) elif command == 'testinvoke': self.test_invoke_contract(arguments) elif command == 'withdraw_request': self.do_request_withdraw(arguments) elif command == 'withdraw': self.do_withdraw_from(arguments) elif command == 'mem': self.show_mem() elif command == 'nodes' or command == 'node': self.show_nodes() elif command == 'state': self.show_state() elif command == 'config': self.configure(arguments) elif command is None: print('please specify a command') else: print("command %s not found" % command) except Exception as e: print("could not execute command: %s " % e) traceback.print_stack() traceback.print_exc()
def MakeTransaction(self, tx, change_address=None, fee=Fixed8(0), from_addr=None, use_standard=False, watch_only_val=0, exclude_vin=None, use_vins_for_asset=None): """ This method is used to to calculate the necessary TransactionInputs (CoinReferences) and TransactionOutputs to be used when creating a transaction that involves an exchange of system assets, ( NEO, Gas, etc ). Args: tx (Transaction): The Transaction to be used. change_address (UInt160): The address any change for the transaction should be returned to. fee (Fixed8): A fee to be attached to the Transaction for network processing purposes. from_addr (UInt160): If present, all CoinReferences selected will only come from this address. use_standard (bool): If true, only CoinReferences from standard addresses ( not contracts that are smart contracts ) will be used. watch_only_val (int): 0 or CoinState.WATCH_ONLY, if present only choose coins that are in a WatchOnly address. exclude_vin (list): A list of CoinReferences to NOT use in the making of this tx. use_vins_for_asset (list): A list of CoinReferences to use. Returns: tx: (Transaction) Returns the transaction with oupdated inputs and outputs. """ tx.ResetReferences() tx.ResetHashData() if not tx.outputs: tx.outputs = [] if not tx.inputs: tx.inputs = [] fee = fee + (tx.SystemFee() * Fixed8.FD()) # pdb.set_trace() paytotal = {} if tx.Type != int.from_bytes(TransactionType.IssueTransaction, 'little'): for key, group in groupby(tx.outputs, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Value paytotal[key] = sum else: paytotal = {} if fee > Fixed8.Zero(): if Blockchain.SystemCoin().Hash in paytotal.keys(): paytotal[Blockchain.SystemCoin(). Hash] = paytotal[Blockchain.SystemCoin().Hash] + fee else: paytotal[Blockchain.SystemCoin().Hash] = fee paycoins = {} self._vin_exclude = exclude_vin for assetId, amount in paytotal.items(): if use_vins_for_asset is not None and len( use_vins_for_asset ) > 0 and use_vins_for_asset[1] == assetId: paycoins[assetId] = self.FindCoinsByVins(use_vins_for_asset[0]) else: paycoins[assetId] = self.FindUnspentCoinsByAssetAndTotal( assetId, amount, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) self._vin_exclude = None for key, unspents in paycoins.items(): if unspents is None: logger.error("insufficient funds for asset id: %s " % key) return None input_sums = {} for assetId, unspents in paycoins.items(): sum = Fixed8(0) for coin in unspents: sum = sum + coin.Output.Value input_sums[assetId] = sum if not change_address: change_address = self.GetChangeAddress(from_addr=from_addr) new_outputs = [] for assetId, sum in input_sums.items(): if sum > paytotal[assetId]: difference = sum - paytotal[assetId] output = TransactionOutput(AssetId=assetId, Value=difference, script_hash=change_address) new_outputs.append(output) inputs = [] for item in paycoins.values(): for ref in item: inputs.append(ref.Reference) tx.inputs = inputs tx.outputs = tx.outputs + new_outputs return tx
def main(): parser = argparse.ArgumentParser() parser.add_argument("-m", "--mainnet", action="store_true", default=False, help="use MainNet instead of the default TestNet") parser.add_argument("-c", "--config", action="store", help="Use a specific config file") # Where to store stuff parser.add_argument("--datadir", action="store", help="Absolute path to use for database directories") parser.add_argument("-i", "--input", help="Where the input file lives") parser.add_argument("-t", "--totalblocks", help="Total blocks to import", type=int) parser.add_argument("-l", "--logevents", help="Log Smart Contract Events", default=False, action="store_true") args = parser.parse_args() if args.mainnet and args.config: print( "Cannot use both --config and --mainnet parameters, please use only one." ) exit(1) # Setting the datadir must come before setting the network, else the wrong path is checked at net setup. if args.datadir: settings.set_data_dir(args.datadir) # Setup depending on command line arguments. By default, the testnet settings are already loaded. if args.config: settings.setup(args.config) elif args.mainnet: settings.setup_mainnet() if args.logevents: settings.log_smart_contract_events = True if not args.input: raise Exception("Please specify an input path") file_path = args.input with open(file_path, 'rb') as file: total_blocks = int.from_bytes(file.read(4), 'little') target_dir = os.path.join(settings.DATA_DIR_PATH, settings.LEVELDB_PATH) notif_target_dir = os.path.join(settings.DATA_DIR_PATH, settings.NOTIFICATION_DB_PATH) print("Will import %s blocks to %s" % (total_blocks, target_dir)) print( "This will overwrite any data currently in %s and %s.\nType 'confirm' to continue" % (target_dir, notif_target_dir)) confirm = prompt("[confirm]> ", is_password=False) if not confirm == 'confirm': print("Cancelled operation") return False try: if os.path.exists(target_dir): shutil.rmtree(target_dir) if os.path.exists(notif_target_dir): shutil.rmtree(notif_target_dir) except Exception as e: print("Could not remove existing data %s " % e) return False # Instantiate the blockchain and subscribe to notifications blockchain = LevelDBBlockchain(settings.chain_leveldb_path) Blockchain.RegisterBlockchain(blockchain) chain = Blockchain.Default() for index in trange(total_blocks, desc='Importing Blocks', unit=' Block'): block_len = int.from_bytes(file.read(4), 'little') stream = StreamManager.GetStream(file.read(block_len)) reader = BinaryReader(stream) block = Block() block.Deserialize(reader) StreamManager.ReleaseStream(stream) if block.Index > 0: chain.AddBlockDirectly(block) file.close() print("Imported %s blocks to %s " % (total_blocks, target_dir))
def __init__(self, path, passwordKey, create): """ Args: path (str): A path indicating where to create or open the wallet. passwordKey (str): A password to use in creating or opening the wallet. create (bool): Whether to create the wallet or simply open. """ self.AddressVersion = settings.ADDRESS_VERSION self._path = path if create: self._iv = bytes(Random.get_random_bytes(16)) self._master_key = bytes(Random.get_random_bytes(32)) self._keys = {} self._contracts = {} self._coins = {} if Blockchain.Default() is None: self._indexedDB = LevelDBBlockchain(settings.LEVELDB_PATH) Blockchain.RegisterBlockchain(self._indexedDB) else: self._indexedDB = Blockchain.Default() self._current_height = 0 self.BuildDatabase() passwordHash = hashlib.sha256(passwordKey).digest() master = AES.new(passwordKey, AES.MODE_CBC, self._iv) mk = master.encrypt(self._master_key) self.SaveStoredData('PasswordHash', passwordHash) self.SaveStoredData('IV', self._iv) self.SaveStoredData('MasterKey', mk) self.SaveStoredData('MigrationState', '1') self.SaveStoredData('Height', self._current_height.to_bytes(4, 'little')) else: self.BuildDatabase() passwordHash = self.LoadStoredData('PasswordHash') if passwordHash is None: raise Exception("Password hash not found in database") hkey = hashlib.sha256(passwordKey).digest() if self.LoadStoredData('MigrationState') != '1': raise Exception("This wallet is currently vulnerable. Please " "execute the \"reencrypt_wallet.py\" script " "on this wallet before continuing") if passwordHash is not None and passwordHash != hkey: raise Exception("Incorrect Password") self._iv = self.LoadStoredData('IV') master_stored = self.LoadStoredData('MasterKey') aes = AES.new(passwordKey, AES.MODE_CBC, self._iv) self._master_key = aes.decrypt(master_stored) self._keys = self.LoadKeyPairs() self._contracts = self.LoadContracts() self._watch_only = self.LoadWatchOnly() self._tokens = self.LoadNEP5Tokens() self._coins = self.LoadCoins() try: h = int(self.LoadStoredData('Height')) self._current_height = h except Exception as e: logger.error("Could not load height data %s " % e) self._current_height = 0 del passwordKey
def __init__(self, path): super(LevelDBBlockchain, self).__init__() self._path = path self._header_index = [] self._header_index.append( Blockchain.GenesisBlock().Header.Hash.ToBytes()) try: self._db = plyvel.DB(self._path, create_if_missing=True) # self._db = plyvel.DB(self._path, create_if_missing=True, bloom_filter_bits=16, compression=None) except Exception as e: logger.info( "leveldb unavailable, you may already be running this process: %s " % e) raise Exception('Leveldb Unavailable') version = self._db.get(DBPrefix.SYS_Version) if version == self._sysversion: # or in the future, if version doesn't equal the current version... ba = bytearray(self._db.get(DBPrefix.SYS_CurrentBlock, 0)) self._current_block_height = int.from_bytes(ba[-4:], 'little') ba = bytearray(self._db.get(DBPrefix.SYS_CurrentHeader, 0)) current_header_height = int.from_bytes(ba[-4:], 'little') current_header_hash = bytes(ba[:64].decode('utf-8'), encoding='utf-8') # logger.info("current header hash!! %s " % current_header_hash) # logger.info("current header height, hashes %s %s %s" %(self._current_block_height, self._header_index, current_header_height) ) hashes = [] try: for key, value in self._db.iterator( prefix=DBPrefix.IX_HeaderHashList): ms = StreamManager.GetStream(value) reader = BinaryReader(ms) hlist = reader.Read2000256List() key = int.from_bytes(key[-4:], 'little') hashes.append({'k': key, 'v': hlist}) StreamManager.ReleaseStream(ms) # hashes.append({'index':int.from_bytes(key, 'little'), 'hash':value}) except Exception as e: logger.info("Could not get stored header hash list: %s " % e) if len(hashes): hashes.sort(key=lambda x: x['k']) genstr = Blockchain.GenesisBlock().Hash.ToBytes() for hlist in hashes: for hash in hlist['v']: if hash != genstr: self._header_index.append(hash) self._stored_header_count += 1 if self._stored_header_count == 0: headers = [] for key, value in self._db.iterator( prefix=DBPrefix.DATA_Block): dbhash = bytearray(value)[8:] headers.append( Header.FromTrimmedData(binascii.unhexlify(dbhash), 0)) headers.sort(key=lambda h: h.Index) for h in headers: if h.Index > 0: self._header_index.append(h.Hash.ToBytes()) elif current_header_height > self._stored_header_count: try: hash = current_header_hash targethash = self._header_index[-1] newhashes = [] while hash != targethash: header = self.GetHeader(hash) newhashes.insert(0, header) hash = header.PrevHash.ToBytes() self.AddHeaders(newhashes) except Exception as e: pass else: with self._db.write_batch() as wb: for key, value in self._db.iterator(): wb.delete(key) self.Persist(Blockchain.GenesisBlock()) self._db.put(DBPrefix.SYS_Version, self._sysversion)
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) 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 do_quit(): print('Shutting down.') Blockchain.Default().Dispose() reactor.stop() NodeLeader.Instance().Shutdown() sys.exit(0)
def GAS(self): return Blockchain.Default().SystemCoin().Hash
def test_invoke(script, wallet, outputs, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE): # print("invoke script %s " % script) if from_addr is not None: from_addr = lookup_addr_str(wallet, from_addr) bc = GetBlockchain() sn = bc._db.snapshot() accounts = DBCollection(bc._db, sn, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, sn, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, sn, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, sn, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, sn, DBPrefix.ST_Storage, StorageItem) # if we are using a withdrawal tx, don't recreate the invocation tx # also, we don't want to reset the inputs / outputs # since those were already calculated if withdrawal_tx is not None: tx = withdrawal_tx else: tx = InvocationTransaction() tx.outputs = outputs tx.inputs = [] tx.Version = 1 tx.scripts = [] tx.Script = binascii.unhexlify(script) script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) if len(outputs) < 1: contract = wallet.GetDefaultContract() tx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False).Data) ] # same as above. we don't want to re-make the transaction if it is a withdrawal tx if withdrawal_tx is not None: wallet_tx = tx else: wallet_tx = wallet.MakeTransaction(tx=tx, from_addr=from_addr) if wallet_tx: context = ContractParametersContext(wallet_tx) wallet.Sign(context) if context.Completed: wallet_tx.scripts = context.GetScripts() engine = ApplicationEngine(trigger_type=TriggerType.Application, container=wallet_tx, table=script_table, service=service, gas=wallet_tx.Gas, testMode=True) engine.LoadScript(wallet_tx.Script, False) try: # drum roll? success = engine.Execute() service.ExecutionCompleted(engine, success) for event in service.events_to_dispatch: events.emit(event.event_type, event) if success: # this will be removed in favor of neo.EventHub if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) print("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() net_fee = None tx_gas = None if consumed <= Fixed8.Zero(): net_fee = min_fee tx_gas = Fixed8.Zero() else: tx_gas = consumed net_fee = Fixed8.Zero() # set the amount of gas the tx will need wallet_tx.Gas = tx_gas # reset the wallet outputs wallet_tx.outputs = outputs wallet_tx.Attributes = [] return wallet_tx, net_fee, engine.EvaluationStack.Items, engine.ops_processed # this allows you to to test invocations that fail else: wallet_tx.outputs = outputs wallet_tx.Attributes = [] return wallet_tx, min_fee, [], engine.ops_processed except Exception as e: service.ExecutionCompleted(engine, False, e) # print("COULD NOT EXECUTE %s " % e) return None, None, None, None
def Assets(self): if not self._assets: self._assets = Blockchain.Default().GetStates(DBPrefix.ST_Asset, AssetState) return self._assets