def ScriptHash(self): if self._scriptHash is None: try: self._scriptHash = Crypto.ToScriptHash(self.Script) except binascii.Error: self._scriptHash = Crypto.ToScriptHash(self.Script, unhex=False) except Exception as e: logger.error("Could not create script hash: %s " % e) return self._scriptHash
async def verify_signature(message): """ Verifies a signature of a message, return True if verified, false if not """ Crypto.SetupSignatureCurve() try: signature = json.loads(message['signature']) except Exception: LOGGER.exception("NEO Signature deserialization error") return False try: script_hash = Crypto.ToScriptHash("21" + signature['publicKey'] + "ac") address = Crypto.ToAddress(script_hash) except Exception: LOGGER.exception("NEO Signature Key error") return False if address != message['sender']: LOGGER.warning('Received bad signature from %s for %s' % (address, message['sender'])) return False try: verification = await buildNEOVerification(message, signature['salt']) result = Crypto.VerifySignature(verification, bytes.fromhex(signature['data']), bytes.fromhex(signature['publicKey']), unhex=True) except Exception: LOGGER.exception("NULS Signature verification error") result = False return result
def GenesisBlock() -> Block: """ Create the GenesisBlock. Returns: BLock: """ prev_hash = UInt256(data=bytearray(32)) timestamp = int( datetime(2016, 7, 15, 15, 8, 21, tzinfo=pytz.utc).timestamp()) index = 0 consensus_data = 2083236893 # Pay tribute To Bitcoin next_consensus = Blockchain.GetConsensusAddress( Blockchain.StandbyValidators()) script = Witness(bytearray(0), bytearray(PUSHT)) mt = MinerTransaction() mt.Nonce = 2083236893 output = TransactionOutput( Blockchain.SystemShare().Hash, Blockchain.SystemShare().Amount, Crypto.ToScriptHash( Contract.CreateMultiSigRedeemScript( int(len(Blockchain.StandbyValidators()) / 2) + 1, Blockchain.StandbyValidators()))) it = IssueTransaction([], [output], [], [script]) return Block( prev_hash, timestamp, index, consensus_data, next_consensus, script, [mt, Blockchain.SystemShare(), Blockchain.SystemCoin(), it], True)
def IsWalletTransaction(self, tx): """ Verifies if a transaction belongs to the wallet. Args: tx (TransactionOutput):an instance of type neo.Core.TX.Transaction.TransactionOutput to verify. Returns: bool: True, if transaction belongs to wallet. False, if not. """ for key, contract in self._contracts.items(): for output in tx.outputs: if output.ScriptHash.ToBytes() == contract.ScriptHash.ToBytes( ): return True for script in tx.scripts: if script.VerificationScript: if bytes(contract.Script) == script.VerificationScript: return True for watch_script_hash in self._watch_only: for output in tx.outputs: if output.ScriptHash == watch_script_hash: return True for script in tx.scripts: if Crypto.ToScriptHash(script.VerificationScript, unhex=False) == watch_script_hash: return True return False
def execute(self, arguments): wallet = PromptData.Wallet if len(arguments) < 3: print("Please specify the minimum required parameters") return False pubkey_in_wallet = arguments[0] if not PromptUtils.is_valid_public_key(pubkey_in_wallet): print("Invalid public key format") return False key_script_hash = Crypto.ToScriptHash(pubkey_in_wallet, unhex=True) if not wallet.ContainsKeyHash(key_script_hash): print("Supplied first public key does not exist in own wallet.") return False try: min_signature_cnt = int(arguments[1]) except ValueError: print(f"Invalid minimum signature count value: {arguments[1]}") return False if min_signature_cnt < 1: print("Minimum signatures count cannot be lower than 1") return False # validate minimum required signing key count signing_keys = arguments[2:] signing_keys.append(pubkey_in_wallet) len_signing_keys = len(signing_keys) if len_signing_keys < min_signature_cnt: # we need at least 2 public keys in total otherwise it's just a regular address. # 1 pub key is from an address in our own wallet, a secondary key can come from any place. print( f"Missing remaining signing keys. Minimum required: {min_signature_cnt} given: {len_signing_keys}" ) return False # validate remaining pub keys for key in signing_keys: if not PromptUtils.is_valid_public_key(key): print(f"Invalid signing key {key}") return False # validate that all signing keys are unique if len(signing_keys) > len(set(signing_keys)): print("Provided signing keys are not unique") return False verification_contract = Contract.CreateMultiSigContract( key_script_hash, min_signature_cnt, signing_keys) address = verification_contract.Address wallet.AddContract(verification_contract) print(f"Added multi-sig contract address {address} to wallet") return True
def is_valid_public_key(key): if len(key) != 66: return False try: Crypto.ToScriptHash(key, unhex=True) except Exception: # the UINT160 inside ToScriptHash can throw Exception return False else: return True
def GetAddress(self): """ Returns the public NEO address for this KeyPair Returns: str: The private key """ script = b'21' + self.PublicKey.encode_point(True) + b'ac' script_hash = Crypto.ToScriptHash(script) address = Crypto.ToAddress(script_hash) return address
def ScriptHash(self): """ Get the script hash. Returns: UInt160: """ if self._scriptHash is None: self._scriptHash = Crypto.ToScriptHash(self.Script, unhex=False) return self._scriptHash
def ContainsKey(self, public_key): """ Test if the wallet contains the supplied public key. Args: public_key (edcsa.Curve.point): a public key to test for its existance. e.g. KeyPair.PublicKey Returns: bool: True if exists, False otherwise. """ return self.ContainsKeyHash( Crypto.ToScriptHash(public_key.encode_point(True), unhex=True))
def GetConsensusAddress(validators): """ Get the script hash of the consensus node. Args: validators (list): of Ellipticcurve.ECPoint's Returns: UInt160: """ vlen = len(validators) script = Contract.CreateMultiSigRedeemScript( vlen - int((vlen - 1) / 3), validators) return Crypto.ToScriptHash(script)
def Sign(self, NEP2orPrivateKey, NEP2password=None, multisig_args=[]): """ Sign the raw transaction Args: NEP2orPrivateKey: (str) the NEP2 or PrivateKey string from the address you are sending from. NOTE: Assumes WIF if NEP2password is None. NEP2password: (str, optional) the NEP2 password associated with the NEP2 key string. Defaults to None. multisig_args: (list, optional) the arguments for importing a multsig address (e.g. [<owner pubkey>, <num required sigs>, [<signing pubkey>, ...]]) """ temp_path = "temp_wallet.wallet" temp_password = "******" wallet = UserWallet.Create(temp_path, to_aes_key(temp_password), generate_default_key=False) if NEP2password: private_key = KeyPair.PrivateKeyFromNEP2(NEP2orWIF, NEP2password) else: private_key = binascii.unhexlify(NEP2orPrivateKey) wallet.CreateKey(private_key) if multisig_args: # import a multisig address verification_contract = Contract.CreateMultiSigContract( Crypto.ToScriptHash(multisig_args[0], unhex=True), multisig_args[1], multisig_args[2]) wallet.AddContract(verification_contract) if self.Type == b'\xd1' and not self.SOURCE_SCRIPTHASH: # in case of an invocation with no funds transfer context = ContractParametersContext(self) elif not self._context: # used during transactions involving a funds transfer signer_contract = wallet.GetContract(self.SOURCE_SCRIPTHASH) context = ContractParametersContext( self, isMultiSig=signer_contract.IsMultiSigContract) else: context = self._context # used for a follow-on signature for a multi-sig transaction wallet.Sign(context) if context.Completed: self.scripts = context.GetScripts() self.Validate() # ensure the tx is ready to be relayed elif context.ContextItems: self._context = context print( "Transaction initiated, but the signature is incomplete. Sign again with another valid multi-sig keypair." ) else: raise SignatureError("Unable to sign transaction.") wallet.Close() wallet = None os.remove(temp_path)
def __init__(self, priv_key): """ Create an instance. Args: priv_key (bytes): a private key. Raises: ValueError: if the input `priv_key` length is not 32, 96, or 104 if the input `priv_key` length is 32 but the public key still could not be determined """ self.setup_curve() self.PublicKeyHash = None self.PublicKey = None self.PrivateKey = None length = len(priv_key) if length != 32 and length != 96 and length != 104: raise ValueError("Invalid private key") self.PrivateKey = bytearray(priv_key[-32:]) pubkey_encoded_not_compressed = None if length == 32: try: pubkey_encoded_not_compressed = bitcoin.privkey_to_pubkey( priv_key) except Exception: raise ValueError("Could not determine public key") elif length == 96 or length == 104: skip = length - 96 pubkey_encoded_not_compressed = bytearray(b'\x04') + bytearray( priv_key[skip:skip + 64]) if pubkey_encoded_not_compressed: pubkey_points = bitcoin.decode_pubkey( pubkey_encoded_not_compressed, 'bin') pubx = pubkey_points[0] puby = pubkey_points[1] edcsa = ECDSA.secp256r1() self.PublicKey = edcsa.Curve.point(pubx, puby) self.PublicKeyHash = Crypto.ToScriptHash( self.PublicKey.encode_point(True), unhex=True)
def SystemShare(): """ Register AntShare. Returns: RegisterTransaction: """ amount = Fixed8.FromDecimal( sum(Blockchain.GENERATION_AMOUNT) * Blockchain.DECREMENT_INTERVAL) owner = ECDSA.secp256r1().Curve.Infinity admin = Crypto.ToScriptHash(PUSHT) return RegisterTransaction( [], [], AssetType.GoverningToken, "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]", amount, 0, owner, admin)
def CreateSignatureContract(publicKey): """ Create a signature contract. Args: publicKey (edcsa.Curve.point): e.g. KeyPair.PublicKey. Returns: neo.SmartContract.Contract: a Contract instance. """ script = Contract.CreateSignatureRedeemScript(publicKey) params = b'\x00' encoded = publicKey.encode_point(True) pubkey_hash = Crypto.ToScriptHash(encoded, unhex=True) return Contract(script, params, pubkey_hash)
def SystemCoin(): """ Register AntCoin Returns: RegisterTransaction: """ amount = Fixed8.FromDecimal( sum(Blockchain.GENERATION_AMOUNT) * Blockchain.DECREMENT_INTERVAL) owner = ECDSA.secp256r1().Curve.Infinity precision = 8 admin = Crypto.ToScriptHash(PUSHF) return RegisterTransaction( [], [], AssetType.UtilityToken, "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]", amount, precision, owner, admin)
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 test_issue_tx(self): miner_tx = MinerTransaction() miner_tx.Nonce = 2083236893 share_tx = GetSystemShare() coin_tx = GetSystemCoin() script = Contract.CreateMultiSigRedeemScript( int(len(Blockchain.StandbyValidators()) / 2) + 1, Blockchain.StandbyValidators()) if settings.MAGIC == 1953787457: self.assertEqual(script, self.contractraw) out = Crypto.ToScriptHash(script) output = TransactionOutput(share_tx.Hash, Blockchain.SystemShare().Amount, out) script = Witness(bytearray(0), bytearray(PUSHT)) issue_tx = IssueTransaction([], [output], [], [script]) self.assertEqual(issue_tx.GetHashData(), self.issuetx_rraw) self.assertEqual(issue_tx.Hash.ToBytes(), self.gen_issue_tx_id)
def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, debug_map=None, invoke_attrs=None, owners=None): bc = GetBlockchain() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBCollection(debug_storage.db, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) except (ValueError, TXFeeError): pass 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, unhex=False)) ] dtx.Attributes = make_unique_script_attr(dtx.Attributes) to_dispatch = [] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=dtx, table=script_table, service=service, gas=dtx.Gas, testMode=True) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke d_success = engine.Execute() if d_success: items = engine.ResultStack.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() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() invoke_args, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments( invoke_args) invoke_args, no_parse_addresses = PromptUtils.get_parse_addresses( invoke_args) invoke_args.reverse() if '--i' in invoke_args: invoke_args = [] for index, iarg in enumerate(contract_state.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, [], 0, None else: invoke_args.append(param) invoke_args.reverse() sb = ScriptBuilder() for p in invoke_args: item = PromptUtils.parse_param(p, wallet, parse_addr=no_parse_addresses) if type(item) is list: item.reverse() listlength = len(item) for listitem in item: subitem = PromptUtils.parse_param( listitem, wallet, parse_addr=no_parse_addresses) if type(subitem) is list: subitem.reverse() for listitem2 in subitem: subsub = PromptUtils.parse_param( listitem2, wallet, parse_addr=no_parse_addresses) sb.push(subsub) sb.push(len(subitem)) sb.Emit(PACK) else: sb.push(subitem) 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 = deepcopy(invoke_attrs) if invoke_attrs else [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1 and not owners: contract = wallet.GetDefaultContract() itx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) itx.Attributes = make_unique_script_attr(itx.Attributes) try: itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) except (ValueError, TXFeeError): pass context = ContractParametersContext(itx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: itx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) itx.Attributes = make_unique_script_attr(itx.Attributes) context = ContractParametersContext(itx, isMultiSig=True) if context.Completed: itx.scripts = context.GetScripts() else: logger.warn( "Not gathering signatures for test build. For a non-test invoke that would occur here." ) # if not gather_signatures(context, itx, owners): # return None, [], 0, None # print("gathered signatures %s " % itx.scripts) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=itx, table=script_table, service=service, gas=itx.Gas, testMode=invocation_test_mode) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) i_success = engine.Execute() service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None
def Contract_Create(self, engine: ExecutionEngine): script = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(script) > 1024 * 1024: return False param_list = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(param_list) > 252: return False return_type = int( engine.CurrentContext.EvaluationStack.Pop().GetBigInteger()) if return_type < 0 or return_type > 0xff: raise ValueError("Invalid return type data popped from stack") contract_properties = int( engine.CurrentContext.EvaluationStack.Pop().GetBigInteger()) if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False name = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False code_version = engine.CurrentContext.EvaluationStack.Pop( ).GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False author = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False email = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 65536: return False description = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ) hash = Crypto.ToScriptHash(script, unhex=False) contract = self.Snapshot.Contracts.TryGet(hash.ToBytes()) if contract is None: try: code = FunctionCode(script=script, param_list=param_list, return_type=return_type, contract_properties=contract_properties) except ValueError: # exception is caused by an invalid `return_type`. neo-cli accepts this , but we throw an exception # this is a dirty hack to work around the VM state difference that it causes until neo-cli hopefully fixes it # see https://github.com/neo-project/neo/issues/827 code = FunctionCode(script=script, param_list=param_list, contract_properties=contract_properties) code.ReturnType = return_type contract = ContractState(code, contract_properties, name, code_version, author, email, description) self.Snapshot.Contracts.Add(code.ScriptHash().ToBytes(), contract) self._contracts_created[hash.ToBytes()] = UInt160( data=engine.CurrentContext.ScriptHash()) engine.CurrentContext.EvaluationStack.PushT( StackItem.FromInterface(contract)) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.CONTRACT_CREATED, ContractParameter( ContractParameterType.InteropInterface, contract), hash, GetBlockchain().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) return True
def VerifyWitnesses(verifiable, snapshot): """ Verify the scripts of the provided `verifiable` object. Args: verifiable (neo.IO.Mixins.VerifiableMixin): Returns: bool: True if verification is successful. False otherwise. """ try: hashes = verifiable.GetScriptHashesForVerifying(snapshot) except Exception as e: logger.debug("couldn't get script hashes %s " % e) return False if len(hashes) != len(verifiable.Scripts): logger.debug(f"hash - verification script length mismatch ({len(hashes)}/{len(verifiable.Scripts)})") return False blockchain = GetBlockchain() for i in range(0, len(hashes)): verification = verifiable.Scripts[i].VerificationScript if len(verification) == 0: sb = ScriptBuilder() sb.EmitAppCall(hashes[i].Data) verification = sb.ms.getvalue() sb.ms.Cleanup() else: verification_hash = Crypto.ToScriptHash(verification, unhex=False) if hashes[i] != verification_hash: logger.debug(f"hash {hashes[i]} does not match verification hash {verification_hash}") return False engine = neo.SmartContract.ApplicationEngine.ApplicationEngine(TriggerType.Verification, verifiable, snapshot, Fixed8.Zero()) engine.LoadScript(verification) invocation = verifiable.Scripts[i].InvocationScript engine.LoadScript(invocation) try: success = engine.Execute() engine._Service.ExecutionCompleted(engine, success) except Exception as e: engine._Service.ExecutionCompleted(engine, False, e) if engine.ResultStack.Count != 1 or not engine.ResultStack.Pop().GetBoolean(): for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) if engine.ResultStack.Count > 0: logger.debug( f"Result stack failure! Count: {engine.ResultStack.Count} bool value: {engine.ResultStack.Pop().GetBoolean()}") else: logger.debug(f"Result stack failure! Count: {engine.ResultStack.Count}") return False for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) return True
def test_gather_param(self): with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='hello') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.String) self.assertEqual(result, 'hello') with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='1') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1.03) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="bytearray(b'abc')") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="b'abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="abc") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, True) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=0) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, False) # test ContractParameterType.ByteArray for address input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='AeV59NyZtgj5AMQ7vY6yhr2MRvcfFeLWSb' ) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual( result, bytearray( b'\xf9\x1dkp\x85\xdb|Z\xaf\t\xf1\x9e\xee\xc1\xca<\r\xb2\xc6\xec' )) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c"]') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array) self.assertEqual(result, ['a', 'b', 'c']) with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"]') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array) self.assertEqual(result, ['a', 'b', 'c', [1, 3, 4], 'e']) # test ContractParameterType.Array without a closed list with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array, do_continue=False) self.assertEqual(result, None) self.assertEqual(abort, True) # test ContractParameterType.Array with no list with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="b'abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array, do_continue=False) self.assertRaises(Exception, "Please provide a list") self.assertEqual(result, None) self.assertEqual(abort, True) # test ContractParameterType.PublicKey with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value= "03cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6" ) as fake_prompt: test_wallet_path = shutil.copyfile( WalletFixtureTestCase.wallet_1_path(), WalletFixtureTestCase.wallet_1_dest()) wallet = UserWallet.Open( test_wallet_path, to_aes_key(WalletFixtureTestCase.wallet_1_pass())) addr_scripthash = wallet.GetStandardAddress() result, abort = Utils.gather_param(0, ContractParameterType.PublicKey) script = b'21' + result.encode_point(True) + b'ac' pk_script_hash = Crypto.ToScriptHash(script) self.assertEqual( addr_scripthash, pk_script_hash ) # verifies the functionality of ContractParameterType.PublicKey wallet.Close() wallet = None os.remove(WalletFixtureTestCase.wallet_1_dest()) # test ContractParameterType.PublicKey with bad public key with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="blah") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.PublicKey) self.assertIsNone(result) self.assertTrue(abort) # test unknown ContractParameterType with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="9698b1cac6ce9cbe8517e490778525b929e01903" ) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Hash160, do_continue=False) self.assertRaises(Exception, "Unknown param type Hash160") self.assertEqual(result, None) self.assertEqual(abort, True) # test Exception with mock.patch('sys.stdout', new=StringIO()) as mock_print: with mock.patch( 'neo.Prompt.Utils.get_input_prompt') as fake_prompt: fake_prompt.side_effect = [ Exception(-32602, "Invalid params"), KeyboardInterrupt ] result, abort = Utils.gather_param( 0, ContractParameterType.String) self.assertEqual(result, None) self.assertEqual(abort, True) self.assertIn("Invalid params", mock_print.getvalue()) # test KeyboardInterrupt with mock.patch('sys.stdout', new=StringIO()) as mock_print: with mock.patch( 'neo.Prompt.Utils.get_input_prompt') as fake_prompt: fake_prompt.side_effect = [KeyboardInterrupt] result, abort = Utils.gather_param( 0, ContractParameterType.String) self.assertEqual(result, None) self.assertEqual(abort, True) self.assertIn("Input cancelled", mock_print.getvalue())
def VerifyScripts(verifiable): """ Verify the scripts of the provided `verifiable` object. Args: verifiable (neo.IO.Mixins.VerifiableMixin): Returns: bool: True if verification is successful. False otherwise. """ try: hashes = verifiable.GetScriptHashesForVerifying() except Exception as e: logger.debug("couldn't get script hashes %s " % e) return False if len(hashes) != len(verifiable.Scripts): logger.debug( f"hash - verification script length mismatch ({len(hashes)}/{len(verifiable.Scripts)})" ) return False blockchain = GetBlockchain() for i in range(0, len(hashes)): verification = verifiable.Scripts[i].VerificationScript if len(verification) == 0: sb = ScriptBuilder() sb.EmitAppCall(hashes[i].Data) verification = sb.ms.getvalue() else: verification_hash = Crypto.ToScriptHash(verification, unhex=False) if hashes[i] != verification_hash: logger.debug( f"hash {hashes[i]} does not match verification hash {verification_hash}" ) return False state_reader = GetStateReader() script_table = CachedScriptTable( DBCollection(blockchain._db, DBPrefix.ST_Contract, ContractState)) engine = ApplicationEngine(TriggerType.Verification, verifiable, script_table, state_reader, Fixed8.Zero()) engine.LoadScript(verification) invocation = verifiable.Scripts[i].InvocationScript engine.LoadScript(invocation) try: success = engine.Execute() state_reader.ExecutionCompleted(engine, success) except Exception as e: state_reader.ExecutionCompleted(engine, False, e) if engine.ResultStack.Count != 1 or not engine.ResultStack.Pop( ).GetBoolean(): Helper.EmitServiceEvents(state_reader) if engine.ResultStack.Count > 0: logger.debug( f"Result stack failure! Count: {engine.ResultStack.Count} bool value: {engine.ResultStack.Pop().GetBoolean()}" ) else: logger.debug( f"Result stack failure! Count: {engine.ResultStack.Count}" ) return False Helper.EmitServiceEvents(state_reader) return True
def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, debug_map=None, invoke_attrs=None, owners=None, enable_debugger=False, snapshot=None): if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBInterface(debug_storage.db, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) except (ValueError): pass context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() contract = wallet.GetDefaultContract() dtx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False))] dtx.Attributes = make_unique_script_attr(dtx.Attributes) to_dispatch = [] if snapshot is None: snapshot = GetBlockchain()._db.createSnapshot().Clone() engine = ApplicationEngine( trigger_type=TriggerType.Application, container=dtx, snapshot=snapshot, gas=dtx.Gas, testMode=True ) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke if enable_debugger: debugger = Debugger(engine) d_success = debugger.Execute() else: d_success = engine.Execute() # the old setup provided the same StateMachine object to the ApplicationEngine for deploy and invoke # this allowed for a single dispatch of events at the end of the function. Now a new StateMachine is automatically # created when creating an ApplicationEngine, thus we have to dispatch events after the deploy to not lose them as # testcases expect them to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) to_dispatch = [] if d_success: items = engine.ResultStack.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() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() invoke_args, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments(invoke_args) invoke_args, no_parse_addresses = PromptUtils.get_parse_addresses(invoke_args) invoke_args.reverse() if '--i' in invoke_args: invoke_args = [] for index, iarg in enumerate(contract_state.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, [], 0, None else: invoke_args.append(param) invoke_args.reverse() sb = ScriptBuilder() for p in invoke_args: process_params(sb, p, wallet, no_parse_addresses) 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 = deepcopy(invoke_attrs) if invoke_attrs else [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1 and not owners: contract = wallet.GetDefaultContract() itx.Attributes.append(TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) itx.Attributes = make_unique_script_attr(itx.Attributes) try: itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) except (ValueError): pass context = ContractParametersContext(itx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: itx.Attributes.append(TransactionAttribute(usage=TransactionAttributeUsage.Script, data=owner)) itx.Attributes = make_unique_script_attr(itx.Attributes) context = ContractParametersContext(itx, isMultiSig=True) if context.Completed: itx.scripts = context.GetScripts() else: logger.warn("Not gathering signatures for test build. For a non-test invoke that would occur here.") engine = ApplicationEngine( trigger_type=TriggerType.Application, container=itx, snapshot=snapshot, gas=itx.Gas, testMode=invocation_test_mode ) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) if enable_debugger: debugger = Debugger(engine) i_success = debugger.Execute() else: i_success = engine.Execute() engine._Service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: if len(engine._Service.notifications) > 0: for n in engine._Service.notifications: Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") # service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None
def CheckWitnessPubkey(self, engine, pubkey): scripthash = Contract.CreateSignatureRedeemScript(pubkey) return self.CheckWitnessHash(engine, Crypto.ToScriptHash(scripthash))
def Contract_Create(self, engine: ExecutionEngine): script = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(script) > 1024 * 1024: return False param_list = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(param_list) > 252: return False return_type = int( engine.CurrentContext.EvaluationStack.Pop().GetBigInteger()) contract_properties = int( engine.CurrentContext.EvaluationStack.Pop().GetBigInteger()) if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False name = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False code_version = engine.CurrentContext.EvaluationStack.Pop( ).GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False author = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False email = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 65536: return False description = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ) hash = Crypto.ToScriptHash(script, unhex=False) contract = self._contracts.TryGet(hash.ToBytes()) if contract is None: code = FunctionCode(script=script, param_list=param_list, return_type=return_type, contract_properties=contract_properties) contract = ContractState(code, contract_properties, name, code_version, author, email, description) self._contracts.GetAndChange(code.ScriptHash().ToBytes(), contract) self._contracts_created[hash.ToBytes()] = UInt160( data=engine.CurrentContext.ScriptHash()) engine.CurrentContext.EvaluationStack.PushT( StackItem.FromInterface(contract)) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.CONTRACT_CREATED, ContractParameter( ContractParameterType.InteropInterface, contract), hash, Blockchain.Default().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) return True
def Contract_Migrate(self, engine: ExecutionEngine): script = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(script) > 1024 * 1024: return False param_list = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() if len(param_list) > 252: return False return_type = int( engine.CurrentContext.EvaluationStack.Pop().GetBigInteger()) contract_properties = engine.CurrentContext.EvaluationStack.Pop( ).GetBigInteger() if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False name = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ).decode('utf-8') if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False version = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ).decode('utf-8') if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False author = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ).decode('utf-8') if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 252: return False email = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ).decode('utf-8') if len(engine.CurrentContext.EvaluationStack.Peek().GetByteArray() ) > 65536: return False description = engine.CurrentContext.EvaluationStack.Pop().GetByteArray( ).decode('utf-8') hash = Crypto.ToScriptHash(script, unhex=False) contract = self._contracts.TryGet(hash.ToBytes()) if contract is None: code = FunctionCode(script=script, param_list=param_list, return_type=return_type) contract = ContractState(code=code, contract_properties=contract_properties, name=name, version=version, author=author, email=email, description=description) self._contracts.Add(hash.ToBytes(), contract) self._contracts_created[hash.ToBytes()] = UInt160( data=engine.CurrentContext.ScriptHash()) if contract.HasStorage: for key, val in self._storages.Find( engine.CurrentContext.ScriptHash()).items(): key = StorageKey(script_hash=hash, key=key) item = StorageItem(val) self._storages.Add(key.ToArray(), item) engine.CurrentContext.EvaluationStack.PushT( StackItem.FromInterface(contract)) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.CONTRACT_MIGRATED, ContractParameter( ContractParameterType.InteropInterface, contract), hash, Blockchain.Default().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) return self.Contract_Destroy(engine)