def test_parse(self): string = '0xd7678dd97c000be3f33e9362e673101bac4ca654' uint160 = UInt160.ParseString(string) self.assertIsInstance(uint160, UInt160) self.assertEqual(uint160.To0xString(), string) string = '5b7074e873973a6ed3708862f219a6fbf4d1c411' uint160 = UInt160.ParseString(string) self.assertIsInstance(uint160, UInt160) self.assertEqual(uint160.ToString(), string) string = '5b7074e873973a6ed3708862f219a6fbf4d1c41' with self.assertRaises(ValueError) as context: uint160 = UInt160.ParseString(string) self.assertIn(f"Invalid UInt160 input: {len(string)} chars != 40 chars", context)
def get_by_contract(self, contract_hash): """ Look up a set of notifications by the contract they are associated with Args: contract_hash (UInt160 or str): hash of contract for notifications to be retreived Returns: list: a list of notifications """ hash = contract_hash if isinstance(contract_hash, str) and len(contract_hash) == 40: hash = UInt160.ParseString(contract_hash) if not isinstance(hash, UInt160): raise Exception("Incorrect address format") contractlist_snapshot = self.db.getPrefixedDB( NotificationPrefix.PREFIX_CONTRACT).createSnapshot() results = [] with contractlist_snapshot.db.openIter( DBProperties(prefix=bytes(hash.Data), include_key=False)) as it: for val in it: if len(val) > 4: try: event = SmartContractEvent.FromByteArray(val) results.append(event) except Exception as e: logger.error("could not parse event: %s %s" % (e, val)) return results
def execute(self, arguments): item = get_arg(arguments) if item is not None: if item.lower() == "all": contracts = Blockchain.Default().ShowAllContracts() contractlist = [] for contract in contracts: state = Blockchain.Default().GetContract( contract.decode('utf-8')).ToJson() contract_dict = {state['name']: state['hash']} contractlist.append(contract_dict) print(json.dumps(contractlist, indent=4)) return contractlist try: hash = UInt160.ParseString(item).ToBytes() except Exception: print("Could not find contract from args: %s" % arguments) return contract = Blockchain.Default().GetContract(hash) if contract is not None: contract.DetermineIsNEP5() print(json.dumps(contract.ToJson(), indent=4)) return contract.ToJson() else: print("Contract %s not found" % item) return else: print('Please specify the required parameter') return
def execute(self, arguments): wallet = PromptData.Wallet if len(arguments) != 1: print("Please specify the required parameter") return False hash_string = arguments[0] try: script_hash = UInt160.ParseString(hash_string) except Exception: # because UInt160 throws a generic exception. Should be fixed in the future print("Invalid script hash") return False # try to find token and collect some data try: token = ModelNEP5Token.get(ContractHash=script_hash) except peewee.DoesNotExist: print(f"Could not find a token with script_hash {arguments[0]}") return False success = wallet.DeleteNEP5Token(script_hash) if success: print( f"Token {token.Symbol} with script_hash {arguments[0]} deleted" ) else: # probably unreachable to due token check earlier. Better safe than sorrow print(f"Could not find a token with script_hash {arguments[0]}") return success
def get_by_contract(self, request, contract_hash): request.setHeader('Content-Type', 'application/json') try: hash = UInt160.ParseString(contract_hash) notifications = self.notif.get_by_contract(hash) except Exception as e: logger.info("Could not get notifications for contract %s " % contract_hash) return self.format_message("Could not get notifications for contract hash %s because %s" % (contract_hash, e)) return self.format_notifications(request, notifications)
def scripthash_to_address(scripthash): try: if scripthash[0:2] != "0x": # litle endian. convert to big endian now. print("Detected little endian scripthash. Converting to big endian for internal use.") scripthash_bytes = binascii.unhexlify(scripthash) scripthash = "0x%s" % binascii.hexlify(scripthash_bytes[::-1]).decode("utf-8") print("Big endian scripthash:", scripthash) return Crypto.ToAddress(UInt160.ParseString(scripthash)) except Exception as e: raise ConversionError("Wrong format")
def execute(self, arguments): if len(arguments) != 1: print("Please specify the required parameter") return try: contract_hash = UInt160.ParseString(arguments[0]).ToBytes() except Exception: print(f"Invalid contract hash: {arguments[0]}") return return ImportToken(PromptData.Wallet, contract_hash)
async def get_by_contract(self, request): contract_hash = request.match_info['contract_hash'] try: hash = UInt160.ParseString(contract_hash) notifications = self.notif.get_by_contract(hash) except Exception as e: logger.info("Could not get notifications for contract %s " % contract_hash) return self.format_message( "Could not get notifications for contract hash %s because %s" % (contract_hash, e)) return self.format_notifications(request, notifications)
def GetContract(self, hash): if type(hash) is str: try: hash = UInt160.ParseString(hash).ToBytes() except Exception as e: logger.info("could not convert argument to bytes :%s " % e) return None contracts = DBCollection(self._db, DBPrefix.ST_Contract, ContractState) contract = contracts.TryGet(keyval=hash) return contract
def example2(): source_address = "AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3" source_script_hash = address_to_scripthash(source_address) # start by creating a base InvocationTransaction # the inputs, outputs and Type do not have to be set anymore. invocation_tx = InvocationTransaction() # Since we are building a raw transaction, we will add the raw_tx flag invocation_tx.raw_tx = True # often times smart contract developers use the function ``CheckWitness`` to determine if the transaction is signed by somebody eligible of calling a certain method # in order to pass that check you want to add the corresponding script_hash as a transaction attribute (this is generally the script_hash of the public key you use for signing) # Note that for public functions like the NEP-5 'getBalance' and alike this would not be needed, but it doesn't hurt either invocation_tx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=source_script_hash)) # next we need to build a 'script' that gets executed against the smart contract. # this is basically the script that calls the entry point of the contract with the necessary parameters smartcontract_scripthash = UInt160.ParseString( "31730cc9a1844891a3bafd1aa929a4142860d8d3") sb = ScriptBuilder() # call the NEP-5 `name` method on the contract (assumes contract address is a NEP-5 token) sb.EmitAppCallWithOperation(smartcontract_scripthash, 'name') invocation_tx.Script = binascii.unhexlify(sb.ToArray()) # at this point we've build our unsigned transaction and it's time to sign it before we get the raw output that we can send to the network via RPC # we need to create a Wallet instance for helping us with signing wallet = UserWallet.Create('path', to_aes_key('mypassword'), generate_default_key=False) # if you have a WIF use the following # this WIF comes from the `neo-test1-w.wallet` fixture wallet private_key = KeyPair.PrivateKeyFromWIF( "Ky94Rq8rb1z8UzTthYmy1ApbZa9xsKTvQCiuGUZJZbaDJZdkvLRV") # if you have a NEP2 encrypted key use the following instead # private_key = KeyPair.PrivateKeyFromNEP2("NEP2 key string", "password string") # we add the key to our wallet wallet.CreateKey(private_key) # and now we're ready to sign context = ContractParametersContext(invocation_tx) wallet.Sign(context) invocation_tx.scripts = context.GetScripts() raw_tx = invocation_tx.ToArray() return raw_tx
def get_token(self, request, contract_hash): request.setHeader('Content-Type', 'application/json') try: uint160 = UInt160.ParseString(contract_hash) contract_event = self.notif.get_token(uint160) if not contract_event: return self.format_message("Could not find contract with hash %s" % contract_hash) notifications = [contract_event] except Exception as e: logger.info("Could not get contract with hash %s because %s " % (contract_hash, e)) return self.format_message("Could not get contract with hash %s because %s " % (contract_hash, e)) return self.format_notifications(request, notifications)
async def get_token(self, request): contract_hash = request.match_info['contract_hash'] try: uint160 = UInt160.ParseString(contract_hash) contract_event = self.notif.get_token(uint160) if not contract_event: return self.format_message( "Could not find contract with hash %s" % contract_hash) notifications = [contract_event] except Exception as e: logger.info("Could not get contract with hash %s because %s " % (contract_hash, e)) return self.format_message( "Could not get contract with hash %s because %s " % (contract_hash, e)) return self.format_notifications(request, notifications)
def FromJson(json): """ Convert a json object to a ContractParameter object Args: item (dict): The item to convert to a ContractParameter object Returns: ContractParameter """ type = ContractParameterType.FromString(json['type']) value = json['value'] param = ContractParameter(type=type, value=None) if type == ContractParameterType.Signature or type == ContractParameterType.ByteArray: param.Value = bytearray.fromhex(value) elif type == ContractParameterType.Boolean: param.Value = bool(value) elif type == ContractParameterType.Integer: param.Value = int(value) elif type == ContractParameterType.Hash160: param.Value = UInt160.ParseString(value) elif type == ContractParameterType.Hash256: param.Value = UInt256.ParseString(value) # @TODO Not sure if this is working... elif type == ContractParameterType.PublicKey: param.Value = ECDSA.decode_secp256r1(value).G elif type == ContractParameterType.String: param.Value = str(value) elif type == ContractParameterType.Array: val = [ContractParameter.FromJson(item) for item in value] param.Value = val return param
def execute(self, arguments): wallet = PromptData.Wallet if len(arguments) != 2: print("Please specify the required parameters") return try: contract_hash = UInt160.ParseString(arguments[0]).ToBytes() except Exception: print(f"Invalid contract hash: {arguments[0]}") return pubkey = arguments[1] if not PromptUtils.is_valid_public_key(pubkey): print(f"Invalid pubkey: {arguments[1]}") return pubkey_script_hash = Crypto.ToScriptHash(pubkey, unhex=True) return ImportContractAddr(wallet, contract_hash, pubkey_script_hash)
def BuildTokenTransfer(self, token, to_addr, amount): """ Build a token transfer for an InvocationTransaction. Args: token: (str) the asset symbol or asset hash to_addr: (str) the destination NEO address (e.g. 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3') amount: (int/decimal) the amount of the asset to send """ if not self.BALANCE: raise RawTXError( 'Please specify a source address before building a token transfer.' ) if not isinstance(token, str): raise TypeError('Please enter your token as a string.') # check if the token is in the source addr balance t_hash = None if len(token) == 40: # check if token is a scripthash for asset in self.BALANCE: if asset['asset_hash'] == token: t_hash = asset['asset_hash'] # also verify not insufficient funds if asset['amount'] < amount: raise AssetError("Insufficient funds.") break else: # assume the symbol was used for asset in self.BALANCE: if asset['asset_symbol'] == token: t_hash = asset['asset_hash'] # also verify not insufficient funds if asset['amount'] < amount: raise AssetError("Insufficient funds.") break if not t_hash: raise AssetError( f'Token {token} not found in the source address balance.') dest_scripthash = Helper.AddrStrToScriptHash( to_addr) # also verifies if the address is valid sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs( UInt160.ParseString(t_hash), 'transfer', [ self.SOURCE_SCRIPTHASH.Data, dest_scripthash.Data, BigInteger(Fixed8.FromDecimal(amount).value) ]) script = sb.ToArray() self.Version = 1 self.Script = binascii.unhexlify(script) # check to see if the source address has been added as a script attribute and add it if not found s = 0 for attr in self.Attributes: if attr.Usage == TransactionAttributeUsage.Script: s = s + 1 if s == 0: self.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=self.SOURCE_SCRIPTHASH)) if s > 1: raise TXAttributeError( 'The script attribute must be used to verify the source address.' )
def json_rpc_method_handler(self, method, params): if method == "getaccountstate": acct = Blockchain.Default().GetAccountState(params[0]) if acct is None: try: acct = AccountState(script_hash=Helper.AddrStrToScriptHash(params[0])) except Exception as e: raise JsonRpcError(-2146233033, "One of the identified items was in an invalid format.") return acct.ToJson() elif method == "getassetstate": asset_str = params[0] if asset_str.lower() == 'neo': assetId = Blockchain.Default().SystemShare().Hash elif asset_str.lower() == 'gas': assetId = Blockchain.Default().SystemCoin().Hash else: assetId = UInt256.ParseString(params[0]) asset = Blockchain.Default().GetAssetState(assetId.ToBytes()) if asset: return asset.ToJson() raise JsonRpcError(-100, "Unknown asset") elif method == "getbestblockhash": return '0x%s' % Blockchain.Default().CurrentHeaderHash.decode('utf-8') elif method == "getblock": # this should work for either str or int block = Blockchain.Default().GetBlock(params[0]) if not block: raise JsonRpcError(-100, "Unknown block") return self.get_block_output(block, params) elif method == "getblockcount": return Blockchain.Default().Height + 1 elif method == "getblockhash": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return '0x%s' % Blockchain.Default().GetBlockHash(height).decode('utf-8') else: raise JsonRpcError(-100, "Invalid Height") elif method == "getblocksysfee": height = params[0] if height >= 0 and height <= Blockchain.Default().Height: return Blockchain.Default().GetSysFeeAmountByHeight(height) else: raise JsonRpcError(-100, "Invalid Height") elif method == "getconnectioncount": return len(NodeLeader.Instance().Peers) elif method == "getcontractstate": script_hash = UInt160.ParseString(params[0]) contract = Blockchain.Default().GetContract(script_hash.ToBytes()) if contract is None: raise JsonRpcError(-100, "Unknown contract") return contract.ToJson() elif method == "getrawmempool": return list(map(lambda hash: "0x%s" % hash.decode('utf-8'), NodeLeader.Instance().MemPool.keys())) elif method == "getversion": return { "port": self.port, "nonce": NodeLeader.Instance().NodeId, "useragent": settings.VERSION_NAME } elif method == "getrawtransaction": tx_id = UInt256.ParseString(params[0]) tx, height = Blockchain.Default().GetTransaction(tx_id) if not tx: raise JsonRpcError(-100, "Unknown Transaction") return self.get_tx_output(tx, height, params) elif method == "getstorage": script_hash = UInt160.ParseString(params[0]) key = binascii.unhexlify(params[1].encode('utf-8')) storage_key = StorageKey(script_hash=script_hash, key=key) storage_item = Blockchain.Default().GetStorageItem(storage_key) if storage_item: return storage_item.Value.hex() return None elif method == "gettransactionheight": try: hash = UInt256.ParseString(params[0]) except Exception: # throws exception, not anything more specific raise JsonRpcError(-100, "Unknown transaction") tx, height = Blockchain.Default().GetTransaction(hash) if tx: return height else: raise JsonRpcError(-100, "Unknown transaction") elif method == "gettxout": hash = params[0].encode('utf-8') index = params[1] utxo = Blockchain.Default().GetUnspent(hash, index) if utxo: return utxo.ToJson(index) else: return None elif method == "invoke": shash = UInt160.ParseString(params[0]) contract_parameters = [ContractParameter.FromJson(p) for p in params[1]] sb = ScriptBuilder() sb.EmitAppCallWithJsonArgs(shash, contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokefunction": contract_parameters = [] if len(params) > 2: contract_parameters = [ContractParameter.FromJson(p).ToVM() for p in params[2]] sb = ScriptBuilder() sb.EmitAppCallWithOperationAndArgs(UInt160.ParseString(params[0]), params[1], contract_parameters) return self.get_invoke_result(sb.ToArray()) elif method == "invokescript": script = params[0].encode('utf-8') return self.get_invoke_result(script) elif method == "sendrawtransaction": tx_script = binascii.unhexlify(params[0].encode('utf-8')) transaction = Transaction.DeserializeFromBufer(tx_script) result = NodeLeader.Instance().Relay(transaction) return result elif method == "validateaddress": return self.validateaddress(params) elif method == "getpeers": return self.get_peers() elif method == "getbalance": if self.wallet: return self.get_balance(params) else: raise JsonRpcError(-400, "Access denied.") elif method == "getwalletheight": if self.wallet: return self.wallet.WalletHeight else: raise JsonRpcError(-400, "Access denied.") elif method == "listaddress": if self.wallet: return self.list_address() else: raise JsonRpcError(-400, "Access denied.") elif method == "getnewaddress": if self.wallet: keys = self.wallet.CreateKey() account = Account.get( PublicKeyHash=keys.PublicKeyHash.ToBytes() ) return account.contract_set[0].Address.ToString() else: raise JsonRpcError(-400, "Access denied.") elif method == "sendtoaddress": if self.wallet: contract_tx, fee = self.parse_send_to_address_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee) else: raise JsonRpcError(-400, "Access denied.") elif method == "sendfrom": if self.wallet: contract_tx, address_from, fee, change_addr = self.parse_send_from_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee, address_from=address_from, change_addr=change_addr) else: raise JsonRpcError(-400, "Access denied.") elif method == "sendmany": if self.wallet: contract_tx, fee, change_addr = self.parse_send_many_params(params) return self.process_transaction(contract_tx=contract_tx, fee=fee, change_addr=change_addr) else: raise JsonRpcError(-400, "Access denied.") elif method == "getblockheader": # this should work for either str or int blockheader = Blockchain.Default().GetHeaderBy(params[0]) if not blockheader: raise JsonRpcError(-100, "Unknown block") return self.get_blockheader_output(blockheader, params) raise JsonRpcError.methodNotFound()
def execute(self, arguments): wallet = PromptData.Wallet if not wallet: print("Please open a wallet") return False arguments, from_addr = PromptUtils.get_from_addr(arguments) arguments, priority_fee = PromptUtils.get_fee(arguments) arguments, invoke_attrs = PromptUtils.get_tx_attr_from_args(arguments) arguments, owners = PromptUtils.get_owners_from_params(arguments) arguments, return_type = PromptUtils.get_return_type_from_args(arguments) if len(arguments) < 1: print("Please specify the required parameters") return False hash_string = arguments[0] try: script_hash = UInt160.ParseString(hash_string) except Exception: # because UInt160 throws a generic exception. Should be fixed in the future print("Invalid script hash") return False p_fee = Fixed8.Zero() if priority_fee is not None: p_fee = priority_fee if p_fee is False: logger.debug("invalid fee") return False tx, fee, results, num_ops, engine_success = TestInvokeContract(wallet, arguments, from_addr=from_addr, invoke_attrs=invoke_attrs, owners=owners) if tx and results: if return_type is not None: try: parameterized_results = [ContractParameter.AsParameterType(ContractParameterType.FromString(return_type), item).ToJson() for item in results] except ValueError: logger.debug("invalid return type") return False else: parameterized_results = [ContractParameter.ToParameter(item).ToJson() for item in results] print( "\n-------------------------------------------------------------------------------------------------------------------------------------") print("Test invoke successful") print(f"Total operations: {num_ops}") print(f"Results {str(parameterized_results)}") print(f"Invoke TX GAS cost: {tx.Gas.value / Fixed8.D}") print(f"Invoke TX fee: {fee.value / Fixed8.D}") print( "-------------------------------------------------------------------------------------------------------------------------------------\n") comb_fee = p_fee + fee if comb_fee != fee: print(f"Priority Fee ({p_fee.value / Fixed8.D}) + Invoke TX Fee ({fee.value / Fixed8.D}) = {comb_fee.value / Fixed8.D}\n") print("Enter your password to send this invocation to the network") tx.Attributes = invoke_attrs try: passwd = prompt("[password]> ", is_password=True) except KeyboardInterrupt: print("Invocation cancelled") return False if not wallet.ValidatePassword(passwd): return print("Incorrect password") return InvokeContract(wallet, tx, comb_fee, from_addr=from_addr, owners=owners) else: print("Error testing contract invoke") return False
def test_wallet_import_contract_addr(self): # test with no wallet open with patch('sys.stdout', new=StringIO()) as mock_print: args = ['import', 'contract_addr', 'contract_hash', 'pubkey'] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("open a wallet", mock_print.getvalue()) self.OpenWallet1() # test with not enough arguments (must have 2 arguments) with patch('sys.stdout', new=StringIO()) as mock_print: args = ['import', 'contract_addr'] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("specify the required parameters", mock_print.getvalue()) # test with too many arguments (must have 2 arguments) with patch('sys.stdout', new=StringIO()) as mock_print: args = ['import', 'contract_addr', 'arg1', 'arg2', 'arg3'] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("specify the required parameters", mock_print.getvalue()) # test with invalid contract hash with patch('sys.stdout', new=StringIO()) as mock_print: args = [ 'import', 'contract_addr', 'invalid_contract_hash', '03cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6' ] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("Invalid contract hash", mock_print.getvalue()) # test with valid contract hash but that doesn't exist with patch('sys.stdout', new=StringIO()) as mock_print: args = [ 'import', 'contract_addr', '31730cc9a1844891a3bafd1aa929000000000000', '03cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6' ] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("Could not find contract", mock_print.getvalue()) # test with invalid pubkey with patch('sys.stdout', new=StringIO()) as mock_print: args = [ 'import', 'contract_addr', '31730cc9a1844891a3bafd1aa929a4142860d8d3', 'invalid_pubkey' ] res = CommandWallet().execute(args) self.assertIsNone(res) self.assertIn("Invalid pubkey", mock_print.getvalue()) # test with valid arguments contract_hash = UInt160.ParseString( '31730cc9a1844891a3bafd1aa929a4142860d8d3') with patch('sys.stdout', new=StringIO()) as mock_print: self.assertIsNone(PromptData.Wallet.GetContract(contract_hash)) args = [ 'import', 'contract_addr', '31730cc9a1844891a3bafd1aa929a4142860d8d3', '03cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6' ] res = CommandWallet().execute(args) self.assertIsInstance(res, Contract) self.assertTrue(PromptData.Wallet.GetContract(contract_hash)) self.assertIn("Added contract address", mock_print.getvalue())