Ejemplo n.º 1
0
def new_sharding_transaction(tx_initiator,
                             data_destination,
                             data_value,
                             data_msgdata,
                             data_vrs,
                             code='',
                             salt=b'\x00' * 32,
                             gas=1000000,
                             access_list=None):
    """
    Create and return a sharding transaction. Data will be encoded in the following order

    [destination, value, msg_data, vrs].
    """
    assert len(data_vrs) in (0, 65)
    tx_data = (pad32(data_destination) + pad32(bytes([data_value])) +
               pad32(data_msgdata) + pad32(data_vrs[:32]) +
               pad32(data_vrs[32:64]) + bytes(data_vrs[64:]))
    if access_list is None:
        access_list = [[tx_initiator]]
        if data_destination:
            access_list.append([data_destination])
    return ShardingTransaction(
        chain_id=1,
        shard_id=1,
        to=tx_initiator,
        data=tx_data,
        gas=gas,
        access_list=access_list,
        code=decode_hex(code),
        salt=salt,
    )
Ejemplo n.º 2
0
def test_get_nonce(vm):
    computation, _ = vm.apply_transaction(ShardingTransaction(**merge(DEFAULT_BASE_TX_PARAMS, {
        "data": int_to_big_endian(NONCE_GETTER_ID),
    })))
    assert computation.output == pad32(b"\x00")

    computation, _ = vm.apply_transaction(SIGNED_DEFAULT_TRANSACTION)

    computation, _ = vm.apply_transaction(ShardingTransaction(**merge(DEFAULT_BASE_TX_PARAMS, {
        "data": int_to_big_endian(NONCE_GETTER_ID),
    })))
    assert computation.output == pad32(b"\x01")
Ejemplo n.º 3
0
def ecmul(computation):
    computation.gas_meter.consume_gas(constants.GAS_ECMUL, reason='ECMUL Precompile')

    try:
        result = _ecmull(computation.msg.data)
    except ValidationError:
        raise VMError("Invalid ECMUL parameters")

    result_x, result_y = result
    result_bytes = b''.join((
        pad32(int_to_big_endian(result_x.n)),
        pad32(int_to_big_endian(result_y.n)),
    ))
    computation.output = result_bytes
    return computation
Ejemplo n.º 4
0
def ecmul(computation):
    computation.consume_gas(constants.GAS_ECMUL, reason='ECMUL Precompile')

    try:
        result = _ecmull(computation.msg.data)
    except ValidationError:
        raise VMError("Invalid ECMUL parameters")

    result_x, result_y = result
    result_bytes = b''.join((
        pad32(int_to_big_endian(result_x.n)),
        pad32(int_to_big_endian(result_y.n)),
    ))
    computation.output = result_bytes
    return computation
Ejemplo n.º 5
0
def precompile_ecrecover(computation):
    computation.gas_meter.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile")
    raw_message_hash = computation.msg.data[:32]
    message_hash = pad32r(raw_message_hash)

    v_bytes = pad32r(computation.msg.data[32:64])
    v = big_endian_to_int(v_bytes)

    r_bytes = pad32r(computation.msg.data[64:96])
    r = big_endian_to_int(r_bytes)

    s_bytes = pad32r(computation.msg.data[96:128])
    s = big_endian_to_int(s_bytes)

    try:
        validate_lt_secpk1n(r)
        validate_lt_secpk1n(s)
        validate_lte(v, 28)
        validate_gte(v, 27)
    except ValidationError:
        return computation

    try:
        raw_public_key = ecdsa_raw_recover(message_hash, (v, r, s))
    except ValueError:
        return computation

    public_key = encode_raw_public_key(raw_public_key)
    address = public_key_to_address(public_key)
    padded_address = pad32(address)

    computation.output = padded_address
    return computation
Ejemplo n.º 6
0
def ecrecover(computation):
    computation.gas_meter.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile")
    raw_message_hash = computation.msg.data[:32]
    message_hash = pad32r(raw_message_hash)

    v_bytes = pad32r(computation.msg.data[32:64])
    v = big_endian_to_int(v_bytes)

    r_bytes = pad32r(computation.msg.data[64:96])
    r = big_endian_to_int(r_bytes)

    s_bytes = pad32r(computation.msg.data[96:128])
    s = big_endian_to_int(s_bytes)

    try:
        validate_lt_secpk1n(r, title="ECRecover: R")
        validate_lt_secpk1n(s, title="ECRecover: S")
        validate_lte(v, 28, title="ECRecover: V")
        validate_gte(v, 27, title="ECRecover: V")
    except ValidationError:
        return computation

    canonical_v = v - 27

    try:
        signature = keys.Signature(vrs=(canonical_v, r, s))
        public_key = signature.recover_public_key_from_msg_hash(message_hash)
    except BadSignature:
        return computation

    address = public_key.to_canonical_address()
    padded_address = pad32(address)

    computation.output = padded_address
    return computation
Ejemplo n.º 7
0
 def hash(self) -> bytes:
     header_hash = keccak(
         b''.join((
             int_to_bytes32(self.shard_id),
             int_to_bytes32(self.expected_period_number),
             self.period_start_prevhash,
             self.parent_hash,
             self.transaction_root,
             pad32(self.coinbase),
             self.state_root,
             self.receipt_root,
             int_to_bytes32(self.number),
         ))
     )
     # Hash of Collation header is the right most 26 bytes of `sha3(header)`
     # It's padded to 32 bytes because `bytes32` is easier to handle in Vyper
     return pad32(header_hash[6:])
Ejemplo n.º 8
0
async def test_shard_syncer(n_peers, connections):
    cancel_token = CancelToken("canceltoken")

    PeerTuple = collections.namedtuple("PeerTuple",
                                       ["node", "server", "syncer"])
    peer_tuples = []

    for i in range(n_peers):
        private_key = keys.PrivateKey(pad32(int_to_big_endian(i + 1)))
        port = get_open_port()
        address = Address("127.0.0.1", port, port)

        node = Node(private_key.public_key, address)

        server = ShardingServer(private_key,
                                address,
                                network_id=9324090483,
                                min_peers=0,
                                peer_class=ShardingPeer)
        asyncio.ensure_future(server.run())

        peer_tuples.append(
            PeerTuple(
                node=node,
                server=server,
                syncer=server.syncer,
            ))

    # connect peers to each other
    await asyncio.gather(*[
        peer_tuples[i].server.peer_pool._connect_to_nodes(
            [peer_tuples[j].node]) for i, j in connections
    ])
    for i, j in connections:
        peer_remotes = [
            peer.remote for peer in peer_tuples[i].server.peer_pool.peers
        ]
        assert peer_tuples[j].node in peer_remotes

    # let each node propose and check that collation appears at all other nodes
    for proposer in peer_tuples:
        collation = proposer.syncer.propose()
        await asyncio.wait_for(asyncio.gather(*[
            peer_tuple.syncer.collations_received_event.wait()
            for peer_tuple in peer_tuples if peer_tuple != proposer
        ]),
                               timeout=10)
        for peer_tuple in peer_tuples:
            assert peer_tuple.syncer.shard.get_collation_by_hash(
                collation.hash) == collation

    # stop everything
    cancel_token.trigger()
    await asyncio.gather(
        *[peer_tuple.server.cancel() for peer_tuple in peer_tuples])
    await asyncio.gather(
        *[peer_tuple.syncer.cancel() for peer_tuple in peer_tuples])
Ejemplo n.º 9
0
def ripemd160(computation):
    word_count = ceil32(len(computation.msg.data)) // 32
    gas_fee = constants.GAS_RIPEMD160 + word_count * constants.GAS_RIPEMD160WORD

    computation.gas_meter.consume_gas(gas_fee, reason="RIPEMD160 Precompile")

    # TODO: this only works if openssl is installed.
    hash = hashlib.new('ripemd160', computation.msg.data).digest()
    padded_hash = pad32(hash)
    computation.output = padded_hash
    return computation
Ejemplo n.º 10
0
def ripemd160(computation):
    word_count = ceil32(len(computation.msg.data)) // 32
    gas_fee = constants.GAS_RIPEMD160 + word_count * constants.GAS_RIPEMD160WORD

    computation.gas_meter.consume_gas(gas_fee, reason="RIPEMD160 Precompile")

    # TODO: this only works if openssl is installed.
    hash = hashlib.new('ripemd160', computation.msg.data).digest()
    padded_hash = pad32(hash)
    computation.output = padded_hash
    return computation
Ejemplo n.º 11
0
def ecpairing(computation):
    if len(computation.msg.data) % 192:
        # data length must be an exact multiple of 192
        raise VMError("Invalid ECPAIRING parameters")

    num_points = len(computation.msg.data) // 192
    gas_fee = constants.GAS_ECPAIRING_BASE + num_points * constants.GAS_ECPAIRING_PER_POINT

    computation.gas_meter.consume_gas(gas_fee, reason='ECPAIRING Precompile')

    try:
        result = _ecpairing(computation.msg.data)
    except ValidationError:
        raise VMError("Invalid ECPAIRING parameters")

    if result is True:
        computation.output = pad32(b'\x01')
    elif result is False:
        computation.output = pad32(b'\x00')
    else:
        raise Exception("Invariant: unreachable code path")
    return computation
Ejemplo n.º 12
0
 def encode_for_smc(self) -> bytes:
     encoded = b"".join([
         int_to_bytes32(self.shard_id),
         self.chunk_root,
         int_to_bytes32(self.period),
         pad32(self.proposer_address),
     ])
     if len(encoded) != self.smc_encoded_size:
         raise ValueError("Encoded header size is {} instead of {} bytes".format(
             len(encoded),
             self.smc_encoded_size,
         ))
     return encoded
Ejemplo n.º 13
0
def ecpairing(computation):
    if len(computation.msg.data) % 192:
        # data length must be an exact multiple of 192
        raise VMError("Invalid ECPAIRING parameters")

    num_points = len(computation.msg.data) // 192
    gas_fee = constants.GAS_ECPAIRING_BASE + num_points * constants.GAS_ECPAIRING_PER_POINT

    computation.consume_gas(gas_fee, reason='ECPAIRING Precompile')

    try:
        result = _ecpairing(computation.msg.data)
    except ValidationError:
        raise VMError("Invalid ECPAIRING parameters")

    if result is True:
        computation.output = pad32(b'\x01')
    elif result is False:
        computation.output = pad32(b'\x00')
    else:
        raise Exception("Invariant: unreachable code path")
    return computation
Ejemplo n.º 14
0
    def get_storage(self, address, slot):
        validate_canonical_address(address)
        validate_uint256(slot)

        account = self._get_account(address)
        storage = StateTrie(Trie(self.db, account.storage_root))

        slot_as_key = pad32(int_to_big_endian(slot))

        if slot_as_key in storage:
            encoded_value = storage[slot_as_key]
            return rlp.decode(encoded_value, sedes=rlp.sedes.big_endian_int)
        else:
            return 0
Ejemplo n.º 15
0
    def get_storage(self, address, slot):
        validate_canonical_address(address, title="Storage Address")
        validate_uint256(slot, title="Storage Slot")

        account = self._get_account(address)
        storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root))

        slot_as_key = pad32(int_to_big_endian(slot))

        if slot_as_key in storage:
            encoded_value = storage[slot_as_key]
            return rlp.decode(encoded_value, sedes=rlp.sedes.big_endian_int)
        else:
            return 0
Ejemplo n.º 16
0
def assemble_data_field(user_account_transaction, include_signature=True):
    if include_signature:
        signature = b"".join([
            pad32(int_to_big_endian(user_account_transaction.v)),
            pad32(int_to_big_endian(user_account_transaction.r)),
            pad32(int_to_big_endian(user_account_transaction.s)),
        ])
    else:
        signature = b""

    return b''.join([
        signature,
        pad32(int_to_big_endian(user_account_transaction.nonce)),
        pad32(int_to_big_endian(user_account_transaction.int_gas_price)),
        pad32(int_to_big_endian(user_account_transaction.value)),
        pad32(int_to_big_endian(user_account_transaction.min_block)),
        pad32(int_to_big_endian(user_account_transaction.max_block)),
        pad32(user_account_transaction.destination),
        user_account_transaction.msg_data,
    ])
Ejemplo n.º 17
0
 def hash(self) -> bytes:
     header_hash = keccak(
         b''.join((
             int_to_bytes32(self.shard_id),
             int_to_bytes32(self.expected_period_number),
             self.period_start_prevhash,
             self.parent_hash,
             self.transaction_root,
             pad32(self.coinbase),
             self.state_root,
             self.receipt_root,
             int_to_bytes32(self.number),
         ))
     )
     return header_hash
Ejemplo n.º 18
0
    def set_storage(self, address, slot, value):
        validate_uint256(value, title="Storage Value")
        validate_uint256(slot, title="Storage Slot")
        validate_canonical_address(address, title="Storage Address")

        account = self._get_account(address)
        storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root))

        slot_as_key = pad32(int_to_big_endian(slot))

        if value:
            encoded_value = rlp.encode(value)
            storage[slot_as_key] = encoded_value
        else:
            del storage[slot_as_key]

        self._set_account(address, account.copy(storage_root=storage.root_hash))
Ejemplo n.º 19
0
    def set_storage(self, address, slot, value):
        validate_uint256(value)
        validate_uint256(slot)
        validate_canonical_address(address)

        account = self._get_account(address)
        storage = StateTrie(Trie(self.db, account.storage_root))

        slot_as_key = pad32(int_to_big_endian(slot))

        if value:
            encoded_value = rlp.encode(value)
            storage[slot_as_key] = encoded_value
        else:
            del storage[slot_as_key]

        account.storage_root = storage.root_hash
        self._set_account(address, account)
Ejemplo n.º 20
0
def ecrecover(computation):
    computation.gas_meter.consume_gas(constants.GAS_ECRECOVER,
                                      reason="ECRecover Precompile")
    raw_message_hash = computation.msg.data[:32]
    message_hash = pad32r(raw_message_hash)

    v_bytes = pad32r(computation.msg.data[32:64])
    v = big_endian_to_int(v_bytes)

    r_bytes = pad32r(computation.msg.data[64:96])
    r = big_endian_to_int(r_bytes)

    s_bytes = pad32r(computation.msg.data[96:128])
    s = big_endian_to_int(s_bytes)

    try:
        validate_lt_secpk1n(r, title="ECRecover: R")
        validate_lt_secpk1n(s, title="ECRecover: S")
        validate_lte(v, 28, title="ECRecover: V")
        validate_gte(v, 27, title="ECRecover: V")
    except ValidationError:
        return computation

    canonical_v = v - 27

    try:
        signature = keys.Signature(vrs=(canonical_v, r, s))
        public_key = signature.recover_public_key_from_msg_hash(message_hash)
    except BadSignature:
        return computation

    address = public_key.to_canonical_address()
    padded_address = pad32(address)

    computation.output = padded_address
    return computation
Ejemplo n.º 21
0
def test_sharding_apply_transaction(unvalidated_shard_chain):  # noqa: F811
    chain = unvalidated_shard_chain

    CREATE2_contracts = json.load(
        open(os.path.join(DIR, '../contract_fixtures/CREATE2_contracts.json')))
    simple_transfer_contract = CREATE2_contracts["simple_transfer_contract"]
    CREATE2_contract = CREATE2_contracts["CREATE2_contract"]
    simple_factory_contract_bytecode = CREATE2_contracts[
        "simple_factory_contract"]["bytecode"]

    # First test: simple ether transfer contract
    first_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(simple_transfer_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=simple_transfer_contract['bytecode'],
    )

    vm = chain.get_vm()
    computation, _ = vm.apply_transaction(first_deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used
    assert gas_used > first_deploy_tx.intrinsic_gas
    last_gas_used = gas_used

    # Transfer ether to recipient
    recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c')
    amount = 100
    tx_initiator = decode_hex(simple_transfer_contract['address'])
    transfer_tx = new_sharding_transaction(tx_initiator, recipient, amount,
                                           b'', b'')

    computation, _ = vm.apply_transaction(transfer_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > transfer_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used
    with vm.state.state_db(read_only=True) as state_db:
        assert state_db.get_balance(recipient) == amount

    # Second test: contract that deploy new contract with CREATE2
    second_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(CREATE2_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=CREATE2_contract['bytecode'],
    )

    computation, _ = vm.apply_transaction(second_deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > second_deploy_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used

    # Invoke the contract to deploy new contract
    tx_initiator = decode_hex(CREATE2_contract['address'])
    newly_deployed_contract_address = generate_CREATE2_contract_address(
        int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode))
    invoke_tx = new_sharding_transaction(
        tx_initiator,
        b'',
        0,
        b'',
        b'',
        access_list=[[tx_initiator, pad32(b'')],
                     [newly_deployed_contract_address]])

    computation, _ = vm.apply_transaction(invoke_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > invoke_tx.intrinsic_gas
    with vm.state.state_db(read_only=True) as state_db:
        newly_deployed_contract_address = generate_CREATE2_contract_address(
            int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode))
        assert state_db.get_code(
            newly_deployed_contract_address) == b'\xbe\xef'
        assert state_db.get_storage(decode_hex(CREATE2_contract['address']),
                                    0) == 1
Ejemplo n.º 22
0
def generate_privkey():
    """Generate a new SECP256K1 private key and return it"""
    privkey = ec.generate_private_key(CURVE, default_backend())
    return keys.PrivateKey(pad32(int_to_big_endian(privkey.private_numbers().private_value)))
Ejemplo n.º 23
0
def generate_random_keypair():
    key_object = keys.PrivateKey(
        pad32(int_to_big_endian(random.getrandbits(8 * 32))))
    return key_object.to_bytes(), key_object.public_key.to_canonical_address()
Ejemplo n.º 24
0
def generate_privkey() -> datatypes.PrivateKey:
    """Generate a new SECP256K1 private key and return it"""
    privkey = ec.generate_private_key(CURVE, default_backend())
    return keys.PrivateKey(
        pad32(int_to_big_endian(privkey.private_numbers().private_value)))
Ejemplo n.º 25
0
def get_storage_key(address, slot):
    return keccak(address) + STORAGE_TRIE_PREFIX + pad32(int_to_big_endian(slot))
Ejemplo n.º 26
0
def generate_random_keypair_and_address() -> Tuple[PrivateKey, PublicKey, Address]:
    priv_key = keys.PrivateKey(pad32(int_to_big_endian(random.getrandbits(8 * 32))))
    return priv_key, priv_key.public_key, Address(priv_key.public_key.to_canonical_address())
Ejemplo n.º 27
0
def test_pad_32(value, expected):
    assert pad32(value) == expected
Ejemplo n.º 28
0
def test_contract_with_no_nonce_tracking(
        unvalidated_shard_chain):  # noqa: F811
    chain = unvalidated_shard_chain
    vm = chain.get_vm()

    no_nonce_tracking_contract = nonce_tracking_contracts[
        "no_nonce_tracking_contract"]
    no_nonce_tracking_contract_address = decode_hex(
        no_nonce_tracking_contract['address'])
    deploy_tx = new_sharding_transaction(
        tx_initiator=no_nonce_tracking_contract_address,
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=no_nonce_tracking_contract['bytecode'],
    )
    computation, _ = vm.apply_transaction(deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used
    assert gas_used > deploy_tx.intrinsic_gas
    last_gas_used = gas_used

    # Trigger the contract
    recipient = b''
    nonce = 0
    tx_initiator = no_nonce_tracking_contract_address
    gas_price = 10
    vrs = 64 * b'\xAA' + b'\x01'
    access_list = [[tx_initiator, pad32(b'\x00')]]
    trigger_tx = new_sharding_transaction(
        tx_initiator,
        recipient,
        nonce,
        bytes([gas_price]),
        vrs,
        access_list=access_list,
    )

    with vm.state.state_db(read_only=True) as state_db:
        balance_before_trigger = state_db.get_balance(
            no_nonce_tracking_contract_address)
    computation, _ = vm.apply_transaction(trigger_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > trigger_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used
    with vm.state.state_db(read_only=True) as state_db:
        assert state_db.get_balance(
            tx_initiator) == balance_before_trigger - gas_used * gas_price

    # Replay the same transaciton
    with vm.state.state_db(read_only=True) as state_db:
        balance_before_trigger = state_db.get_balance(
            no_nonce_tracking_contract_address)
    computation, _ = vm.apply_transaction(trigger_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > trigger_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used
    with vm.state.state_db(read_only=True) as state_db:
        # Check that fee is charged since there's no replay protection
        assert state_db.get_balance(
            tx_initiator) == balance_before_trigger - gas_used * gas_price
Ejemplo n.º 29
0
def test_pad_32(value, expected):
    assert pad32(value) == expected