Beispiel #1
0
 def get_exec_fee_factor(self, snapshot: storage.Snapshot) -> int:
     storage_item = snapshot.storages.get(self.key_exec_fee_factor,
                                          read_only=True)
     return int(vm.BigInteger(storage_item.value))
Beispiel #2
0
def get_trigger(engine: contracts.ApplicationEngine) -> vm.BigInteger:
    return vm.BigInteger(engine.trigger.value)
Beispiel #3
0
 def _initialize(self, engine: contracts.ApplicationEngine) -> None:
     engine.snapshot.storages.put(self.key_request_id, storage.StorageItem(vm.BigInteger.zero().to_array()))
     engine.snapshot.storages.put(self.key_price, storage.StorageItem(vm.BigInteger(50000000).to_array()))
Beispiel #4
0
 def get_price(self, snapshot: storage.Snapshot) -> int:
     return int(vm.BigInteger(snapshot.storages.get(self.key_price, read_only=True).value))
 def deserialize(self, reader: serialization.BinaryReader) -> None:
     self.value = vm.BigInteger(reader.read_var_bytes())
Beispiel #6
0
    def _request(self,
                 engine: contracts.ApplicationEngine,
                 url: str,
                 filter: str,
                 callback: str,
                 user_data: vm.StackItem,
                 gas_for_response: int) -> None:
        if len(url.encode('utf-8')) > self._MAX_URL_LENGTH or \
                len(filter.encode('utf-8')) > self._MAX_FILTER_LEN or \
                len(callback.encode('utf-8')) > self._MAX_CALLBACK_LEN or \
                callback.startswith("_") or \
                gas_for_response < 10000000:
            raise ValueError

        engine.add_gas(self.get_price(engine.snapshot))
        engine.add_gas(gas_for_response)
        self._gas.mint(engine, self.hash, vm.BigInteger(gas_for_response), False)

        si_item_id = engine.snapshot.storages.get(self.key_request_id, read_only=False)
        item_id = vm.BigInteger(si_item_id.value)
        si_item_id.value = (item_id + 1).to_array()

        if contracts.ManagementContract().get_contract(engine.snapshot, engine.calling_scripthash) is None:
            raise ValueError

        oracle_request = OracleRequest(self._get_original_txid(engine),
                                       gas_for_response,
                                       url,
                                       filter,
                                       engine.calling_scripthash,
                                       callback,
                                       contracts.BinarySerializer.serialize(user_data, self._MAX_USER_DATA_LEN))
        engine.snapshot.storages.put(self.key_request + int(item_id).to_bytes(8, 'little', signed=False),
                                     storage.StorageItem(oracle_request.to_array())
                                     )

        sk_id_list = self.key_id_list + self._get_url_hash(url)
        si_id_list = engine.snapshot.storages.try_get(sk_id_list, read_only=False)
        if si_id_list is None:
            si_id_list = storage.StorageItem(b'\x00')

        with serialization.BinaryReader(si_id_list.value) as reader:
            count = reader.read_var_int()
            id_list = []
            for _ in range(count):
                id_list.append(reader.read_uint64())

        id_list.append(item_id)
        if len(id_list) >= 256:
            raise ValueError("Oracle has too many pending responses for this url")

        with serialization.BinaryWriter() as writer:
            writer.write_var_int(len(id_list))
            for id in id_list:
                writer.write_uint64(id)
            si_id_list.value = writer.to_array()
        engine.snapshot.storages.update(sk_id_list, si_id_list)

        state = vm.ArrayStackItem(
            engine.reference_counter,
            [vm.IntegerStackItem(item_id),
             vm.ByteStringStackItem(engine.calling_scripthash.to_array()),
             vm.ByteStringStackItem(url.encode()),
             vm.ByteStringStackItem(filter.encode()),
             ]
        )

        msgrouter.interop_notify(self.hash, "OracleRequest", state)
 def __init__(self):
     self.value = vm.BigInteger(1)
    def test_get_transaction_from_block(self):
        # this test for the first part is identical to the GetBlock test above
        engine = test_engine(has_container=True, has_snapshot=True)

        # test with serialized block hash (UInt256). This fake hash won't return a block
        engine.push(vm.IntegerStackItem(0))  # index
        engine.push(vm.ByteStringStackItem(b'\x01' * 32))
        engine.invoke_syscall_by_name(
            "System.Blockchain.GetTransactionFromBlock")
        self.assertIsInstance(engine.pop(), vm.NullStackItem)

        # now find an existing block, but with an invalid transaction index (
        # first add a block and update the snapshot
        # normally this would be done while persisting in Blockchain
        testblock = test_block()
        engine.snapshot.block_height = testblock.index
        engine.snapshot.blocks.put(testblock)
        engine.push(vm.IntegerStackItem(-1))  # index
        engine.push(vm.ByteStringStackItem(
            testblock.hash().to_array()))  # hash
        with self.assertRaises(ValueError) as context:
            engine.invoke_syscall_by_name(
                "System.Blockchain.GetTransactionFromBlock")
        self.assertEqual("Transaction index out of range: -1",
                         str(context.exception))

        # now let's try again but this time with an invalid index (out of bounds)
        engine.push(vm.IntegerStackItem(len(testblock.transactions) +
                                        1))  # index
        engine.push(vm.ByteStringStackItem(
            testblock.hash().to_array()))  # hash
        with self.assertRaises(ValueError) as context:
            engine.invoke_syscall_by_name(
                "System.Blockchain.GetTransactionFromBlock")
        self.assertEqual("Transaction index out of range: 2",
                         str(context.exception))

        # Finally, we try with a valid index (we have only 1 transaction, so 0)
        engine.push(vm.IntegerStackItem(vm.BigInteger(0)))  # index
        engine.push(vm.ByteStringStackItem(
            testblock.hash().to_array()))  # hash
        engine.invoke_syscall_by_name(
            "System.Blockchain.GetTransactionFromBlock")

        # and test the TX items pushed to the stack
        item = engine.pop()
        testblock_tx = testblock.transactions[0]
        self.assertIsInstance(item, vm.ArrayStackItem)
        self.assertEqual(len(item), 8)
        self.assertEqual(item[0].to_array(), testblock_tx.hash().to_array())
        self.assertEqual(item[1].to_biginteger(),
                         vm.BigInteger(testblock_tx.version))
        self.assertEqual(item[2].to_biginteger(),
                         vm.BigInteger(testblock_tx.nonce))
        self.assertEqual(item[3].to_array(), testblock_tx.sender.to_array())
        self.assertEqual(item[4].to_biginteger(),
                         vm.BigInteger(testblock_tx.system_fee))
        self.assertEqual(item[5].to_biginteger(),
                         vm.BigInteger(testblock_tx.network_fee))
        self.assertEqual(item[6].to_biginteger(),
                         vm.BigInteger(testblock_tx.valid_until_block))
        self.assertEqual(item[7].to_array(), testblock_tx.script)
Beispiel #9
0
 def deserialize(self, reader: BinaryReader) -> None:
     self._balance = vm.BigInteger(reader.read_var_bytes())
Beispiel #10
0
 def test_negative_mint(self):
     gas = contracts.GasToken()
     with self.assertRaises(ValueError) as context:
         gas.mint(None, None, vm.BigInteger(-1), False)
     self.assertEqual("Can't mint a negative amount",
                      str(context.exception))
Beispiel #11
0
    def test_on_persist(self):
        """
        OnPersist will do the following
        * burn the system and network fees for all transactions
        * mint the sum of network_fees for all transactions to the address of the consensus node that acted as primary
          speaker for the block
        """
        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        # set or we won't pass the native deploy call
        engine.snapshot.persisting_block = block

        gas = contracts.GasToken()

        # update the TX signer account to point to our validator or the token burn() (part of on persist)
        # will fail because it can't find an account with balance
        mock_signer = mock.MagicMock()
        mock_signer.account = self.validator_account
        engine.snapshot.persisting_block.transactions[0].signers = [
            mock_signer
        ]
        # our consensus_data is not setup in a realistic way, so we have to correct for that here
        # or we fail to get the account of primary consensus node
        engine.snapshot.persisting_block.header.primary_index = settings.network.validators_count - 1

        gas.on_persist(engine)
        """
            Drop the below in a test in UT_NativeContract.cs and change ProtocolSettings.cs to
            * have a ValidatorsCount of 1 
            * and the StandbyCommittee should be: 02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765

            var snapshot = Blockchain.Singleton.GetSnapshot();
            snapshot.PersistingBlock = new Block() { Index = 1000 };
            var point = ECPoint.Parse("02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765", ECCurve.Secp256r1);
            var account = Contract.CreateMultiSigRedeemScript(1, new ECPoint[] {point}).ToScriptHash();
            var tx = TestUtils.GetTransaction(account);
            tx.SystemFee = 456;
            tx.NetworkFee = 789;
            snapshot.PersistingBlock.Transactions = new Transaction[] {tx};
            snapshot.PersistingBlock.ConsensusData = new ConsensusData { PrimaryIndex = 0};

            ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.System, tx, snapshot, 0);
            NativeContract.GAS.OnPersist(engine2);
            var key = new byte[] {0x14};
            var sk  = key.Concat(account.ToArray());
            var item = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = sk.ToArray()});
            var state = item.GetInteroperable<AccountState>();
            Console.WriteLine($"account state {state.Balance}");

            var item2 = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = new byte[]{11}});
            Console.WriteLine($"total supply {(BigInteger)item2}");

            var primary_account = Contract.CreateSignatureRedeemScript(point).ToScriptHash();
            var primary_sk = key.Concat(primary_account.ToArray());
            var primary_item = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = primary_sk.ToArray()});
            var primary_state = primary_item.GetInteroperable<AccountState>();
            Console.WriteLine($"primary account state {primary_state.Balance}");
        """

        # * our validator prior to on_persist had a balance of 30_000_000
        # * after it should have been reduced by the network + system_fee's paid in the transaction
        sk_gas_supply = gas.key_account + self.validator_account
        si_supply = engine.snapshot.storages.try_get(sk_gas_supply)
        self.assertIsNotNone(si_supply)
        token_state = gas._state.deserialize_from_bytes(si_supply.value)
        total_fees = engine.snapshot.persisting_block.transactions[0].network_fee + \
                     engine.snapshot.persisting_block.transactions[0].system_fee
        expected = (30_000_000 * gas.factor) - total_fees
        self.assertEqual(expected, int(token_state.balance))

        # * total GAS supply was 30_000_000 + 0.5 for committee reward, should be reduced by the system_fee
        sk_total_supply = gas.key_total_supply
        si_total_supply = engine.snapshot.storages.try_get(sk_total_supply)
        self.assertIsNotNone(si_total_supply)
        committee_reward = vm.BigInteger(50000000)
        expected = (
            (30_000_000 * gas.factor) + committee_reward
        ) - engine.snapshot.persisting_block.transactions[0].system_fee
        self.assertEqual(expected, vm.BigInteger(si_total_supply.value))

        # * the persisting block contains exactly 1 transaction
        # * after on_persist the account our primary validator should have been credited with the transaction's
        #   network_fee
        primary_validator = to_script_hash(
            contracts.Contract.create_signature_redeemscript(
                self.validator_public_key))
        sk_gas_supply = gas.key_account + primary_validator
        si_supply = engine.snapshot.storages.try_get(sk_gas_supply)
        self.assertIsNotNone(si_supply)
        token_state = gas._state.deserialize_from_bytes(si_supply.value)
        expected = engine.snapshot.persisting_block.transactions[
            0].network_fee + committee_reward
        self.assertEqual(expected, int(token_state.balance))