def CheckDynamicInvoke(self, opcode): cx = self.CurrentContext if opcode in [OpCode.APPCALL, OpCode.TAILCALL]: opreader = cx.OpReader # read the current position of the stream start_pos = opreader.stream.tell() # normal app calls are stored in the op reader # we read ahead past the next instruction 1 the next 20 bytes script_hash = opreader.ReadBytes(21)[1:] # then reset the position opreader.stream.seek(start_pos) for b in script_hash: # if any of the bytes are greater than 0, this is a normal app call if b > 0: return True # if this is a dynamic app call, we will arrive here # get the current executing script hash current = UInt160(data=cx.ScriptHash()) current_contract_state = self._Table.GetContractState(current.ToBytes()) # if current contract state cant do dynamic calls, return False return current_contract_state.HasDynamicInvoke elif opcode in [OpCode.CALL_ED, OpCode.CALL_EDT]: current = UInt160(data=cx.ScriptHash()) current_contract_state = self._Table.GetContractState(current.ToBytes()) return current_contract_state.HasDynamicInvoke else: return True
def CheckDynamicInvoke(self): cx = self.CurrentContext opcode = cx.CurrentInstruction.OpCode if opcode in [OpCode.APPCALL, OpCode.TAILCALL]: script_hash = cx.CurrentInstruction.Operand for b in script_hash: # if any of the bytes are greater than 0, this is a normal app call if b > 0: return True # if this is a dynamic app call, we will arrive here # get the current executing script hash current = UInt160(data=cx.ScriptHash()) current_contract_state = self.snapshot.Contracts[current.ToBytes()] # if current contract state cant do dynamic calls, return False return current_contract_state.HasDynamicInvoke elif opcode in [OpCode.CALL_ED, OpCode.CALL_EDT]: current = UInt160(data=cx.ScriptHash()) current_contract_state = self.snapshot.Contracts[current.ToBytes()] return current_contract_state.HasDynamicInvoke else: return True
class UserWalletTestCaseBase(WalletFixtureTestCase): wallet_1_script_hash = UInt160( data= b'\x1c\xc9\xc0\\\xef\xff\xe6\xcd\xd7\xb1\x82\x81j\x91R\xec!\x8d.\xc0') wallet_1_addr = 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3' _wallet1 = None wallet_2_script_hash = UInt160( data=b'\x08t/\\P5\xac-\x0b\x1c\xb4\x94tIyBu\x7f1*') wallet_2_addr = 'AGYaEi3W6ndHPUmW7T12FFfsbQ6DWymkEm' _wallet2 = None import_watch_addr = UInt160( data=b'\x08t/\\P5\xac-\x0b\x1c\xb4\x94tIyBu\x7f1*') watch_addr_str = 'AGYaEi3W6ndHPUmW7T12FFfsbQ6DWymkEm' @property def GAS(self): return Blockchain.Default().SystemCoin().Hash @property def NEO(self): return Blockchain.Default().SystemShare().Hash @classmethod def GetWallet1(cls, recreate=False): if cls._wallet1 is None or recreate: shutil.copyfile(cls.wallet_1_path(), cls.wallet_1_dest()) cls._wallet1 = UserWallet.Open( UserWalletTestCase.wallet_1_dest(), to_aes_key(UserWalletTestCase.wallet_1_pass())) return cls._wallet1 @classmethod def GetWallet2(cls, recreate=False): if cls._wallet2 is None or recreate: shutil.copyfile(cls.wallet_2_path(), cls.wallet_2_dest()) cls._wallet2 = UserWallet.Open( UserWalletTestCase.wallet_2_dest(), to_aes_key(UserWalletTestCase.wallet_2_pass())) return cls._wallet2 @classmethod def OpenWallet1(cls): PromptData.Wallet = cls.GetWallet1(recreate=True) @classmethod def OpenWallet2(cls): PromptData.Wallet = cls.GetWallet2(recreate=True) @classmethod def tearDown(cls): PromptData.Wallet = None
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 test_dunder_methods(self): u1 = UInt160(b'12345678901234567890') u1b = UIntBase(20, b'12345678901234567890') u_larger = UInt160(b'12345678901234567891') u_smaller = UInt160(b'12345678901234567880') self.assertTrue(u1 < u_larger) self.assertTrue(u1 <= u_larger) self.assertTrue(u1 <= u1b) self.assertTrue(u1 == u1b) self.assertTrue(u1b == u1) self.assertTrue(u1 >= u1b) self.assertTrue(u1 >= u_smaller) self.assertTrue(u1 > u_smaller)
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
class BoaTest(WalletFixtureTestCase): dirname = None FIXTURE_REMOTE_LOC = 'https://s3.us-east-2.amazonaws.com/cityofzion/fixtures/fixtures_v8.tar.gz' FIXTURE_FILENAME = 'fixtures/empty_fixture.tar.gz' wallet_1_script_hash = UInt160( data=b'S\xefB\xc8\xdf!^\xbeZ|z\xe8\x01\xcb\xc3\xac/\xacI)') wallet_1_addr = 'APRgMZHZubii29UXF9uFa6sohrsYupNAvx' _wallet1 = None @classmethod def wallet_1_dest(cls): return os.path.join(settings.DATA_DIR_PATH, 'wallet1.wallet') @classmethod def wallet_1_path(cls): return cls.wallets_folder + 'neo-test1-w.wallet' @classmethod def setUpClass(cls): cls.dirname = '/'.join(os.path.abspath(__file__).split('/')[:-3]) super(BoaTest, cls).setUpClass() @classmethod def GetWallet1(cls, recreate=False): if cls._wallet1 is None or recreate: cls._wallet1 = UserWallet.Open(BoaTest.wallet_1_dest(), to_aes_key(BoaTest.wallet_1_pass())) return cls._wallet1
def Runtime_Log(self, engine: ExecutionEngine): item = engine.CurrentContext.EvaluationStack.Pop() # will raise an exception for types that don't support it item.GetByteArray() # if we pass we can call the convenience method to pretty print the data message = item.GetString() hash = UInt160(data=engine.CurrentContext.ScriptHash()) tx_hash = None if engine.ScriptContainer: tx_hash = engine.ScriptContainer.Hash engine.write_log(str(message)) # Build and emit smart contract event self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.RUNTIME_LOG, ContractParameter(ContractParameterType.String, value=message), hash, GetBlockchain().Height + 1, tx_hash, test_mode=engine.testMode)) return True
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 Storage_GetReadOnlyContext(self, engine: ExecutionEngine): hash = UInt160(data=engine.CurrentContext.ScriptHash()) context = StorageContext(script_hash=hash, read_only=True) engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(context)) return True
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 Storage_Delete(self, engine: ExecutionEngine): context = engine.CurrentContext.EvaluationStack.Pop().GetInterface() if not self.CheckStorageContext(context): return False key = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() storage_key = StorageKey(script_hash=context.ScriptHash, key=key) keystr = key if len(key) == 20: keystr = Crypto.ToAddress(UInt160(data=key)) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.STORAGE_DELETE, ContractParameter(ContractParameterType.String, keystr), context.ScriptHash, Blockchain.Default().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) self._storages.Remove(storage_key.ToArray()) return True
def Contract_Destroy(self, engine): hash = UInt160(data=engine.CurrentContext.ScriptHash()) contract = self._contracts.TryGet(hash.ToBytes()) if contract is not None: self._contracts.Remove(hash.ToBytes()) if contract.HasStorage: for pair in self._storages.Find(hash.ToBytes()): self._storages.Remove(pair.Key) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.CONTRACT_DESTROY, ContractParameter( ContractParameterType.InteropInterface, contract), hash, Blockchain.Default().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) return True
def ToScriptHash(self, address): """ Retrieve the script_hash based from an address. Args: address (str): a base58 encoded address. Raises: ValuesError: if an invalid address is supplied or the coin version is incorrect Exception: if the address string does not start with 'A' or the checksum fails Returns: UInt160: script hash. """ if len(address) == 34: if address[0] == 'A': data = b58decode(address) if data[0] != self.AddressVersion: raise ValueError('Not correct Coin Version') checksum = Crypto.Default().Hash256(data[:21])[:4] if checksum != data[21:]: raise Exception('Address format error') return UInt160(data=data[1:21]) else: raise Exception('Address format error') else: raise ValueError('Not correct Address, wrong length.')
def Blockchain_GetAccount(self, engine: ExecutionEngine): hash = UInt160(data=engine.CurrentContext.EvaluationStack.Pop().GetByteArray()) address = Crypto.ToAddress(hash).encode('utf-8') account = self.Accounts.GetOrAdd(address, new_instance=AccountState(script_hash=hash)) engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(account)) return True
def Contract_Destroy(self, engine): hash = UInt160(data=engine.CurrentContext.ScriptHash()) contract = self.Snapshot.Contracts.TryGet(hash.ToBytes()) if contract is not None: self.Snapshot.Contracts.Delete(hash.ToBytes()) if contract.HasStorage: to_del = [] for k, v in self.Snapshot.Storages.Find(hash.ToArray()): storage_key = StorageKey(script_hash=hash, key=k[20:]) # Snapshot.Storages.Delete() modifies the underlying dictionary of the cache we'd be iterating # over using Storages.Find. We therefore need to postpone deletion to_del.append(storage_key) for storage_key in to_del: self.Snapshot.Storages.Delete(storage_key.ToArray()) self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.CONTRACT_DESTROY, ContractParameter( ContractParameterType.InteropInterface, contract), hash, GetBlockchain().Height + 1, engine.ScriptContainer.Hash if engine.ScriptContainer else None, test_mode=engine.testMode)) return True
def Blockchain_GetContract(self, engine: ExecutionEngine): hash = UInt160(data=engine.CurrentContext.EvaluationStack.Pop().GetByteArray()) contract = self.Contracts.TryGet(hash.ToBytes()) if contract is None: engine.CurrentContext.EvaluationStack.PushT(bytearray(0)) else: engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(contract)) return True
def test_accountstate_ToJson(self): hash = UInt160(data=self.ac2_h) account = AccountState(script_hash=hash) res = account.ToJson() self.assertEqual(res['address'], account.Address) self.assertEqual(res['script_hash'], str(hash))
def _LoadScriptByHash(self, script_hash: bytearray, rvcount=-1): if self._Table is None: return None script = self._Table.GetScript(UInt160(data=script_hash).ToBytes()) if script is None: return None return self._LoadScriptInternal(Script.FromHash(script_hash, script), rvcount)
def Storage_GetContext(self, engine: ExecutionEngine): hash = UInt160(data=engine.CurrentContext.ScriptHash()) context = neo.SmartContract.StorageContext.StorageContext( script_hash=hash) engine.CurrentContext.EvaluationStack.PushT( StackItem.FromInterface(context)) return True
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 test_9_lookup_should_be_empty(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x82N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 0)
def test_7_lookup_addr_by_script_hash(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x81N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 1)
def __init__(self, asset_id=None, asset_type=None, name=None, amount=None, available=None, precision=0, fee_mode=0, fee=None, fee_addr=None, owner=None, admin=None, issuer=None, expiration=None, is_frozen=False): """ Create an instance. Args: asset_id (UInt256): asset_type (neo.Core.AssetType): name (str): the asset name. amount (Fixed8): available (Fixed8): precision (int): number of decimals the asset has. fee_mode (int): fee (Fixed8): fee_addr (UInt160): where the fee will be send to. owner (EllipticCurve.ECPoint): admin (UInt160): the administrator of the asset. issuer (UInt160): the issuer of the asset. expiration (UInt32): the block number on which the asset expires. is_frozen (bool): """ self.AssetId = asset_id self.AssetType = asset_type self.Name = name self.Amount = Fixed8(0) if amount is None else amount self.Available = Fixed8(0) if available is None else available self.Precision = precision self.FeeMode = fee_mode self.Fee = Fixed8(0) if fee is None else fee self.FeeAddress = UInt160( data=bytearray(20)) if fee_addr is None else fee_addr if owner is not None and type(owner) is not EllipticCurve.ECPoint: raise Exception("Owner must be ECPoint Instance") self.Owner = owner self.Admin = admin self.Issuer = issuer self.Expiration = expiration self.IsFrozen = is_frozen
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 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 test_5_addr_conv(self): wallet = self.GetWallet1() addr = UInt160( data=b'\xec\xa8\xfc\xf9Nz*\x7f\xc3\xfdT\xae\x0e\xd3\xd3MR\xec%\x90' ) addr_str = 'AdMDZGto3xWozB1HSjjVv27RL3zUM8LzpV' to_uint = wallet.ToScriptHash(addr_str) self.assertEqual(to_uint, addr)
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 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)
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