def parse_send_many_params(self, params): if type(params[0]) is not list: raise JsonRpcError(-32602, "Invalid params") if len(params) not in [1, 2, 3]: raise JsonRpcError(-32602, "Invalid params") output = [] for info in params[0]: asset = get_asset_id(self.wallet, info['asset']) if not type(asset) is UInt256: raise JsonRpcError(-32602, "Invalid params") address = info["address"] try: address = self.wallet.ToScriptHash(address) except Exception: raise JsonRpcError(-32602, "Invalid params") amount = Fixed8.TryParse(info["value"], require_positive=True) if not amount or float(info["value"]) == 0: raise JsonRpcError(-32602, "Invalid params") tx_output = TransactionOutput(AssetId=asset, Value=amount, script_hash=address) output.append(tx_output) contract_tx = ContractTransaction(outputs=output) fee = Fixed8.TryParse(params[1]) if len(params) >= 2 else Fixed8.Zero() if fee < Fixed8.Zero(): raise JsonRpcError(-32602, "Invalid params") change_addr_sh = None if len(params) >= 3: change_addr = params[2] try: change_addr_sh = self.wallet.ToScriptHash(change_addr) except Exception: raise JsonRpcError(-32602, "Invalid params") return contract_tx, fee, change_addr_sh
def test_build_contract_5(self): """ return from JSON-RPC is: {'state': 'HALT, BREAK', 'script': '4d0004ababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab abababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa babababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab046b657931057075745f356780a1a5b87921dda4603b502ada749890cb ca3434', 'stack': [{'type': 'Integer', 'value': '1'}], 'gas_consumed': '11.151'} """ wallet = self.GetWallet1() arguments = [ "neo/SmartContract/tests/StorageTest.py", "True", "False", "True", "070705", "05", "put_5", "key1", self.big_str ] tx, result, total_ops, engine = BuildAndRun(arguments, wallet, False) expected_cost = Fixed8(1046600000) expected_gas = Fixed8.FromDecimal(1.0) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_gas)
def NetworkFee(self): """ Get the network fee. Returns: Fixed8: """ if self._network_fee is None: input = Fixed8(0) for coin_ref in self.References.values(): if coin_ref.AssetId == GetBlockchain().SystemCoin().Hash: input = input + coin_ref.Value output = Fixed8(0) for tx_output in self.outputs: if tx_output.AssetId == GetBlockchain().SystemCoin().Hash: output = output + tx_output.Value self._network_fee = input - output - self.SystemFee() # logger.info("Determined network fee to be %s " % (self.__network_fee.value)) return self._network_fee
def parse_send_from_params(self, params): if len(params) not in [4, 5, 6]: raise JsonRpcError(-32602, "Invalid params") asset_id = get_asset_id(self.wallet, params[0]) if not type(asset_id) is UInt256: raise JsonRpcError(-32602, "Invalid params") address_from = params[1] try: address_from_sh = self.wallet.ToScriptHash(address_from) except Exception: raise JsonRpcError(-32602, "Invalid params") address_to = params[2] try: address_to_sh = self.wallet.ToScriptHash(address_to) except Exception: raise JsonRpcError(-32602, "Invalid params") amount = Fixed8.TryParse(params[3], require_positive=True) if not amount or float(params[3]) == 0: raise JsonRpcError(-32602, "Invalid params") output = TransactionOutput(AssetId=asset_id, Value=amount, script_hash=address_to_sh) contract_tx = ContractTransaction(outputs=[output]) fee = Fixed8.TryParse(params[4]) if len(params) >= 5 else Fixed8.Zero() if fee < Fixed8.Zero(): raise JsonRpcError(-32602, "Invalid params") change_addr_sh = None if len(params) >= 6: change_addr = params[5] try: change_addr_sh = self.wallet.ToScriptHash(change_addr) except Exception: raise JsonRpcError(-32602, "Invalid params") return contract_tx, address_from_sh, fee, change_addr_sh
def GetTransactionResults(self): """ Get the execution results of the transaction. Returns: None: if the transaction has no references. list: of TransactionResult objects. """ if self.References is None: return None results = [] realresults = [] for ref_output in self.References.values(): results.append( TransactionResult(ref_output.AssetId, ref_output.Value)) for output in self.outputs: results.append( TransactionResult(output.AssetId, output.Value * Fixed8(-1))) for key, group in groupby(results, lambda x: x.AssetId): sum = Fixed8(0) for item in group: sum = sum + item.Amount if sum != Fixed8.Zero(): realresults.append(TransactionResult(key, sum)) return realresults
def get_asset_attachments(params): to_remove = [] neo_to_attach = None gas_to_attach = None for item in params: if type(item) is str: if '--attach-neo=' in item: to_remove.append(item) try: neo_to_attach = Fixed8.TryParse( int(item.replace('--attach-neo=', ''))) except Exception as e: pass if '--attach-gas=' in item: to_remove.append(item) try: gas_to_attach = Fixed8.FromDecimal( float(item.replace('--attach-gas=', ''))) except Exception as e: pass for item in to_remove: params.remove(item) return params, neo_to_attach, gas_to_attach
def test_1_initial_setup(self): wallet = self.GetWallet1() jsn = wallet.ToJson() addr = jsn['addresses'][0] self.assertEqual(self.wallet_1_addr, addr['address']) self.assertEqual(str(Helper.AddrStrToScriptHash(self.wallet_1_addr)), addr['script_hash']) gas_balance_should_be = Fixed8.FromDecimal(13.9998) gas_balance = wallet.GetBalance(self.GAS) self.assertEqual(gas_balance_should_be, gas_balance) neo_balance_should_be = Fixed8.FromDecimal(50) neo_balance = wallet.GetBalance(self.NEO) self.assertEqual(neo_balance_should_be, neo_balance) self.assertEqual(wallet.WalletHeight, 12351)
def test_ICOTemplate_4_attachments(self): output = Compiler.instance().load( '%s/boa_test/example/demo/ICO_Template.py' % TestContract.dirname).default out = output.write() snapshot = self.snapshot # test mint tokens without being kyc verified tx, results, total_ops, engine = TestBuild( out, ['get_attachments', '[]', '--attach-neo=10'], self.GetWallet3(), '0705', '05', snapshot=snapshot) self.assertEqual(len(results), 1) attachments = results[0].GetArray() self.assertEqual(len(attachments), 4) fn = FunctionCode(out, '0705', '05') self.assertEqual(attachments[0].GetByteArray(), fn.ScriptHash().Data) self.assertEqual(attachments[1].GetByteArray(), self.wallet_3_script_hash.Data) self.assertEqual(attachments[2].GetBigInteger(), Fixed8.FromDecimal(10).value) self.assertEqual(attachments[3].GetBigInteger(), 0) tx, results, total_ops, engine = TestBuild(out, ['get_attachments', '[]'], self.GetWallet3(), '0705', '05', snapshot=snapshot) self.assertEqual(len(results), 1) attachments = results[0].GetArray() self.assertEqual(len(attachments), 4) self.assertEqual(attachments[1].GetByteArray(), bytearray()) self.assertEqual(attachments[2].GetBigInteger(), 0) self.assertEqual(attachments[3].GetBigInteger(), 0) tx, results, total_ops, engine = TestBuild( out, ['get_attachments', '[]', '--attach-neo=3', '--attach-gas=3.12'], self.GetWallet1(), '0705', '05', snapshot=snapshot) self.assertEqual(len(results), 1) attachments = results[0].GetArray() self.assertEqual(len(attachments), 4) self.assertEqual(attachments[1].GetByteArray(), self.wallet_1_script_hash.Data) self.assertEqual(attachments[2].GetBigInteger(), Fixed8.FromDecimal(3).value) self.assertEqual(attachments[3].GetBigInteger(), Fixed8.FromDecimal(3.12).value)
def test_utils_8(self): args = [1, 2, '--attach-gas=100.0003', '--attach-neo=6'] args, neo, gas = Utils.get_asset_attachments(args) self.assertEqual(args, [1, 2]) self.assertEqual(neo, Fixed8.FromDecimal(6)) self.assertEqual(gas, Fixed8.FromDecimal(100.0003))
def test_fixed8_add(self): f1 = Fixed8(100) f2 = Fixed8(300) f3 = f1 + f2 self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, 400)
def test_fixed8_sub(self): f1 = Fixed8(100) f2 = Fixed8(300) f3 = f1 - f2 self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, -200)
def test_fixed8_mul(self): f1 = Fixed8(3) f2 = Fixed8(9) f3 = f1 * f2 self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, 27)
def test_fixed8_div(self): f1 = Fixed8(27) f2 = Fixed8(3) f3 = f1 / f2 self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, 9)
def test_fixed8_pow(self): f1 = Fixed8(2) f2 = Fixed8(3) f3 = pow(f1, f2) self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, 8)
def GetSystemFee_Validator(self): if self.Field == "Registered": for character in self.Value: if character != '0': return Fixed8.FromDecimal(1000) return Fixed8.Zero() raise Exception("Invalid operation")
def test_fixed8_floor(self): f8 = Fixed8.FromDecimal(4.9999999999) f8_ceil = f8.Floor() self.assertEqual(f8_ceil, Fixed8.FromDecimal(4)) f8 = Fixed8.FromDecimal(4.2) f8_ceil = f8.Floor() self.assertEqual(f8_ceil, Fixed8.FromDecimal(4))
def test_fixed8_ceil(self): f8 = Fixed8.FromDecimal(4.6) f8_ceil = f8.Ceil() self.assertEqual(f8_ceil, Fixed8.FromDecimal(5)) f8 = Fixed8.FromDecimal(4.00000001) f8_ceil = f8.Ceil() self.assertEqual(f8_ceil, Fixed8.FromDecimal(5))
def AddOutput(self, asset, to_addr, amount): """ Specify an output for the transaction. NOTE: Can be used multiple times to create multiple outputs. Args: asset: (str) the asset name or asset hash to_addr: (str) the destination NEO address (e.g. 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3') amount: (int/decimal) the amount of the asset to send """ if asset[0:1] == "0x": asset == asset[2:] if asset.lower() == "neo": assetId = self.neo_asset_id elif asset == self.neo_asset_id: assetId = self.neo_asset_id elif asset.lower() == "gas": assetId = self.gas_asset_id elif asset == self.gas_asset_id: assetId = self.gas_asset_id else: raise AssetError( f'Asset {asset} not found. If trying to send tokens use the `buildTokenTransfer` function.' ) dest_scripthash = Helper.AddrStrToScriptHash( to_addr) # also verifies if the address is valid if float(amount) == 0: raise ValueError('Amount cannot be 0.') f8amount = Fixed8.TryParse(amount, require_positive=True) if f8amount is None: raise ValueError('Invalid amount format.') elif assetId == self.neo_asset_id and (f8amount.value / Fixed8.D) != f8amount.ToInt(): raise ValueError('Incorrect amount precision.') # check if the outputs exceed the available unspents subtotal = [] if self.outputs: for output in self.outputs: if output.AssetId == assetId: subtotal.append(output.Value.value) total = f8amount.value + sum(subtotal) total = float(Fixed8(total).ToString()) for asset in self.BALANCE: if assetId == asset['asset_hash']: if total > asset['amount']: raise AssetError( 'Total outputs exceed the available unspents.') self.outputs.append( TransactionOutput(AssetId=UInt256.ParseString(assetId), Value=f8amount, script_hash=dest_scripthash))
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 execute(self, arguments): wallet = PromptData.Wallet if len(arguments) < 4: print("Please specify the required parameters") return if len(arguments) > 5: # the 5th argument is the optional attributes, print("Too many parameters supplied. Please check your command") return addr = arguments[0] if not isValidPublicAddress(addr): print("Invalid address specified") return try: from_addr = wallet.ToScriptHash(addr) except ValueError as e: print(str(e)) return asset_id = PromptUtils.get_asset_id(wallet, arguments[1]) if not asset_id: print(f"Unknown asset id: {arguments[1]}") return try: index = int(arguments[2]) except ValueError: print(f"Invalid unspent index value: {arguments[2]}") return try: divisions = int(arguments[3]) except ValueError: print(f"Invalid divisions value: {arguments[3]}") return if divisions < 2: print("Divisions cannot be lower than 2") return if len(arguments) == 5: fee = Fixed8.TryParse(arguments[4], require_positive=True) if not fee: print(f"Invalid fee value: {arguments[4]}") return else: fee = Fixed8.Zero() return SplitUnspentCoin(wallet, asset_id, from_addr, index, divisions, fee)
def test_fixed8_tojsonstring(self): f8 = Fixed8.FromDecimal(1.0) self.assertEqual("1", f8.ToNeoJsonString()) f8 = Fixed8.FromDecimal(1.10) self.assertEqual("1.1", f8.ToNeoJsonString()) f8 = Fixed8.FromDecimal(10) self.assertEqual("10", f8.ToNeoJsonString()) f8 = Fixed8.FromDecimal(100) self.assertEqual("100", f8.ToNeoJsonString()) f8 = Fixed8.FromDecimal(2609.997813) self.assertEqual("2609.997813", f8.ToNeoJsonString())
def FindUnspentCoinsByAssetAndTotal(self, asset_id, amount, from_addr=None, use_standard=False, watch_only_val=0, reverse=False): """ Finds unspent coin objects totalling a requested value in the wallet limited to those of a certain asset type. Args: asset_id (UInt256): a bytearray (len 32) representing an asset on the blockchain. amount (int): the amount of unspent coins that are being requested. from_addr (UInt160): a bytearray (len 20) representing an address. use_standard (bool): whether or not to only include standard contracts ( i.e not a smart contract addr ). watch_only_val (int): a flag ( 0 or 64 ) indicating whether or not to find coins that are in 'watch only' addresses. Returns: list: a list of ``neo.Wallet.Coin`` in the wallet that are not spent. this list is empty if there are not enough coins to satisfy the request. """ coins = self.FindUnspentCoinsByAsset(asset_id, from_addr=from_addr, use_standard=use_standard, watch_only_val=watch_only_val) sum = Fixed8(0) for coin in coins: sum = sum + coin.Output.Value if sum < amount: return None coins = sorted(coins, key=lambda coin: coin.Output.Value.value) if reverse: coins.reverse() total = Fixed8(0) # go through all coins, see if one is an exact match. then we'll use that for coin in coins: if coin.Output.Value == amount: return [coin] to_ret = [] for coin in coins: total = total + coin.Output.Value to_ret.append(coin) if total >= amount: break return to_ret
def test_fixed8_mod(self): f1 = Fixed8(10) f2 = Fixed8(5) f3 = f1 % f2 self.assertIsInstance(f3, Fixed8) self.assertEqual(f3.value, 0) f4 = Fixed8(7) f5 = f1 % f4 self.assertEqual(f5.value, 3)
def Run(snapshot, script, container=None, exit_on_error=False, gas=Fixed8.Zero(), test_mode=True, wb=None): """ Runs a script in a test invoke environment Args: script (bytes): The script to run container (neo.Core.TX.Transaction): [optional] the transaction to use as the script container Returns: ApplicationEngine """ engine = ApplicationEngine(TriggerType.Application, container, snapshot, gas, test_mode) # maybe not the best solution # but one for now if not wb: _script = binascii.unhexlify(script) else: _script = script engine.LoadScript(_script) engine.Execute() for event in engine._Service.events_to_dispatch: events.emit(event.event_type, event) return engine
def test_debug_contract_1(self): wallet = self.GetWallet1() arguments = [ "neo/SmartContract/tests/BreakpointTest.py", "True", "False", "True", "02", "01", "1", ] dbg = VMDebugger # dbg.end = MagicMock(return_value=None) dbg.start = MagicMock(return_value=None) tx, result, total_ops, engine = BuildAndRun( arguments, wallet, False, min_fee=Fixed8.FromDecimal(.0004)) debugger = engine._vm_debugger context = debugger.get_context() context.print_file() self.assertIsInstance(debugger, VMDebugger) self.assertIsInstance(context, DebugContext) self.assertEqual(debugger.index, 29) self.assertEqual(context.method.name, 'Main') self.assertEqual(context.line, 11)
def validate_simple_policy(tx) -> Tuple[bool, str]: """ Validate transaction policies Args: tx: Transaction object Returns: tuple: result: True if it passes the policy checks. False otherwise. error_msg: empty str if policy passes, otherwise reason for failure. """ # verify the maximum tx size is not exceeded if tx.Size() > tx.MAX_TX_SIZE: return False, f"Transaction cancelled. The tx size ({tx.Size()}) exceeds the maximum tx size ({tx.MAX_TX_SIZE})." # calculate and verify the required network fee for the tx fee = tx.NetworkFee() if tx.Size( ) > settings.MAX_FREE_TX_SIZE and not tx.Type == b'\x02': # Claim Transactions are High Priority req_fee = Fixed8.FromDecimal(settings.FEE_PER_EXTRA_BYTE * (tx.Size() - settings.MAX_FREE_TX_SIZE)) if req_fee < settings.LOW_PRIORITY_THRESHOLD: req_fee = settings.LOW_PRIORITY_THRESHOLD if fee < req_fee: return False, f'Transaction cancelled. The tx size ({tx.Size()}) exceeds the max free tx size ({settings.MAX_FREE_TX_SIZE}).\nA network fee of {req_fee.ToString()} GAS is required.' return True, ""
def Verify(self, snapshot, mempool): """ Verify the transaction. Args: mempool: Returns: bool: True if verified. False otherwise. """ logger.debug("Verifying transaction: %s " % self.Hash.ToBytes()) # SimplePolicyPlugin if self.Size() > self.MAX_TX_SIZE: logger.debug( f'Maximum transaction size exceeded: {self.Size()} > {self.MAX_TX_SIZE}' ) return False fee = self.NetworkFee() if self.Size( ) > settings.MAX_FREE_TX_SIZE and not self.Type == b'\x02': # Claim Transactions are High Priority req_fee = Fixed8.FromDecimal( settings.FEE_PER_EXTRA_BYTE * (self.Size() - settings.MAX_FREE_TX_SIZE)) if req_fee < settings.LOW_PRIORITY_THRESHOLD: req_fee = settings.LOW_PRIORITY_THRESHOLD if fee < req_fee: logger.debug( f'The tx size ({self.Size()}) exceeds the max free tx size ({settings.MAX_FREE_TX_SIZE}).\nA network fee of {req_fee.ToString()} GAS is required.' ) return False return SCHelper.Helper.VerifyWitnesses(self, snapshot)
def test_debug_contract_2(self): wallet = self.GetWallet1() arguments = [ "neo/SmartContract/tests/BreakpointTest.py", "True", "False", "True", "02", "01", "4", ] dbg = VMDebugger dbg.start = MagicMock(return_value=None) tx, result, total_ops, engine = BuildAndRun( arguments, wallet, False, min_fee=Fixed8.FromDecimal(.0004), enable_debugger=True) debugger = engine._vm_debugger context = debugger.get_context() context.print() self.assertEqual(debugger.index, 157) self.assertEqual(context.method.name, 'another_method') self.assertEqual(context.line, 38)
def GetBalance(self, asset_id, watch_only=0): """ Get the balance of a specific token by its asset id. Args: asset_id (NEP5Token|TransactionOutput): an instance of type neo.Wallets.NEP5Token or neo.Core.TX.Transaction.TransactionOutput to get the balance from. watch_only (bool): True, to limit to watch only wallets. Returns: Fixed8: total balance. """ total = Fixed8(0) if type(asset_id) is NEP5Token.NEP5Token: return self.GetTokenBalance(asset_id, watch_only) for coin in self.GetCoins(): if coin.Output.AssetId == asset_id: if coin.State & CoinState.Confirmed > 0 and \ coin.State & CoinState.Spent == 0 and \ coin.State & CoinState.Locked == 0 and \ coin.State & CoinState.Frozen == 0 and \ coin.State & CoinState.WatchOnly == watch_only: total = total + coin.Output.Value return total
def CalculateBonusInternal(unclaimed): amount_claimed = Fixed8.Zero() decInterval = Blockchain.DECREMENT_INTERVAL genAmount = Blockchain.GENERATION_AMOUNT genLen = len(genAmount) for coinheight, group in groupby(unclaimed, lambda x: x.Heights): amount = 0 ustart = int(coinheight.start / decInterval) if ustart < genLen: istart = coinheight.start % decInterval uend = int(coinheight.end / decInterval) iend = coinheight.end % decInterval if uend >= genLen: iend = 0 if iend == 0: uend -= 1 iend = decInterval while ustart < uend: amount += (decInterval - istart) * genAmount[ustart] ustart += 1 istart = 0 amount += (iend - istart) * genAmount[ustart] endamount = Blockchain.Default().GetSysFeeAmountByHeight( coinheight.end - 1) startamount = 0 if coinheight.start == 0 else Blockchain.Default( ).GetSysFeeAmountByHeight(coinheight.start - 1) amount += endamount - startamount outputSum = 0 for spentcoin in group: outputSum += spentcoin.Value.value outputSum = outputSum / 100000000 outputSumFixed8 = Fixed8(int(outputSum * amount)) amount_claimed += outputSumFixed8 return amount_claimed