Exemple #1
0
def test_sign():
    """Test collator.sign(msg_hash, privkey)
    """
    msg_hash = utils.sha3('hello')
    privkey = t.k0
    assert sign(msg_hash, privkey) == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1bz\x05\x13\xf6\xa4\xbb\x0c\xaf<\x87\x95\xa7\xf5\x139\x84\x89\\#\x91\x15\x9dPX\x9e\xc9\x01\x8fp\x14\xd2,\x0c\x97\xd6\xbf\xc9\x11\x9d\xf7Z\x99-\xd3\x05\xc6\xf3\xfc\xfbe\x99c1\xcb\x93K\xf0I,\xd7\xebUB%'

    msg_hash2 = utils.sha3('world')
    assert sign(msg_hash2, privkey) == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x10\xcf\xacjd\xa9@\xf44\xd5K[A\xbb\xde&0\xc3V\xe4\x9f\xe9+\xf6\'\x0eVbQtYf"5\x04\x85\xc8\x1dB\x92\xd9\xc9r\xed\x9a\x08\xfet\xce@\xa2\x1bm\x88\xc2\x875\xff\x99\xc5oN\xac\xa4'
Exemple #2
0
def create_collation(chain,
                     shard_id,
                     parent_collation_hash,
                     expected_period_number,
                     coinbase,
                     key,
                     txqueue=None):
    """Create a collation

    chain: MainChain
    shard_id: id of ShardChain
    parent_collation_hash: the hash of the parent collation
    expected_period_number: the period number in which this collation expects to be included
    coinbase: coinbase
    key: key for sig
    txqueue: transaction queue
    """
    log.info('Creating a collation')

    assert chain.has_shard(shard_id)

    temp_state = chain.shards[shard_id].mk_poststate_of_collation_hash(
        parent_collation_hash)
    cs = get_consensus_strategy(temp_state.config)

    # Set period_start_prevblock info
    period_start_prevhash = chain.get_period_start_prevhash(
        expected_period_number)
    assert period_start_prevhash is not None
    period_start_prevblock = chain.get_block(period_start_prevhash)
    # Call the initialize state transition function
    cs.initialize(temp_state, period_start_prevblock)
    # Initialize a collation with the given previous state and current coinbase
    collation = state_transition.mk_collation_from_prevstate(
        chain.shards[shard_id], temp_state, coinbase)
    # Add transactions
    state_transition.add_transactions(temp_state,
                                      collation,
                                      txqueue,
                                      shard_id,
                                      mainchain_state=chain.state)
    # Call the finalize state transition function
    state_transition.finalize(temp_state, collation.header.coinbase)
    # Set state root, receipt root, etc
    state_transition.set_execution_results(temp_state, collation)

    collation.header.shard_id = shard_id
    collation.header.parent_collation_hash = parent_collation_hash
    collation.header.expected_period_number = expected_period_number
    collation.header.period_start_prevhash = period_start_prevhash

    try:
        sig = sign(collation.signing_hash, key)
        collation.header.sig = sig
    except Exception as e:
        log.info('Failed to sign collation, exception: {}'.format(str(e)))
        raise e

    log.info('Created collation successfully')
    return collation
Exemple #3
0
    def collate(self, shard_id, privkey, coinbase=a0):
        """Collate the collation and send a collation-header-transaction
        """
        # Finalize
        assert self.chain.has_shard(shard_id)
        shard_state_transition.finalize(self.shard_head_state[shard_id],
                                        coinbase)
        shard_state_transition.set_execution_results(
            self.shard_head_state[shard_id], self.collation[shard_id])

        # Sign the collation
        collation = self.collation[shard_id]
        collation.header.sig = validator_manager_utils.sign(
            collation.signing_hash, privkey)

        # Add collation to db
        period_start_prevblock = self.chain.get_block(
            self.collation[shard_id].header.period_start_prevhash)
        assert self.chain.shards[shard_id].add_collation(
            collation, period_start_prevblock,
            self.chain.handle_ignored_collation)

        # Create and send add_header tx
        tx = validator_manager_utils.call_tx_add_header(
            self.head_state, privkey, 0,
            rlp.encode(CollationHeader.serialize(collation.header)))
        self.direct_tx(tx)
        self.last_sender = privkey

        return collation
Exemple #4
0
 def sharding_withdraw(self, privkey, validator_index):
     """Withdraw
     """
     signature = validator_manager_utils.sign(
         validator_manager_utils.WITHDRAW_HASH, privkey)
     tx = validator_manager_utils.call_withdraw(self.head_state, privkey, 0,
                                                validator_index, signature)
     self.direct_tx(tx)
     self.last_sender = privkey
Exemple #5
0
def test_call_deposit_withdraw_sample(chain):
    # make validation code
    k0_valcode = mk_validation_code(t.a0)
    tx = create_contract_tx(chain.head_state, t.k0, k0_valcode)
    k0_valcode_addr = chain.direct_tx(tx)
    chain.mine(1)

    # deposit
    tx = call_deposit(chain.head_state, t.k0, DEPOSIT_SIZE, k0_valcode_addr, t.a2)
    chain.direct_tx(tx)
    chain.mine(1)
    assert hex(utils.big_endian_to_int(k0_valcode_addr)) == call_valmgr(chain.head_state, 'sample', [0])

    # withdraw
    tx = call_withdraw(chain.head_state, t.k0, 0, 0, sign(WITHDRAW_HASH, t.k0))
    chain.direct_tx(tx)
    chain.mine(1)
    assert 0 == int(call_valmgr(chain.head_state, 'sample', [0]), 16)
    assert call_validation_code(chain.head_state, k0_valcode_addr, WITHDRAW_HASH, sign(WITHDRAW_HASH, t.k0))
Exemple #6
0
 def get_colhdr(shard_id, parent_collation_hash, collation_coinbase=t.a0):
     period_length = 5
     expected_period_number = num_blocks // period_length
     b = chain.chain.get_block_by_number(expected_period_number * period_length - 1)
     period_start_prevhash = b.header.hash
     tx_list_root = b"tx_list " * 4
     post_state_root = b"post_sta" * 4
     receipt_root = b"receipt " * 4
     sighash = utils.sha3(
         rlp.encode([
             shard_id, expected_period_number, period_start_prevhash,
             parent_collation_hash, tx_list_root, collation_coinbase,
             post_state_root, receipt_root
         ])
     )
     sig = sign(sighash, t.k0)
     return rlp.encode([
         shard_id, expected_period_number, period_start_prevhash,
         parent_collation_hash, tx_list_root, collation_coinbase,
         post_state_root, receipt_root, sig
     ])
Exemple #7
0
def test_validator_manager():
    # Must pay 100 ETH to become a validator

    c = t.Chain(env='sharding', deploy_sharding_contracts=True)

    k0_valcode_addr = c.tx(t.k0, '', 0, mk_validation_code(t.a0))
    k1_valcode_addr = c.tx(t.k1, '', 0, mk_validation_code(t.a1))

    num_blocks = 11
    c.mine(num_blocks - 1, coinbase=t.a0)
    c.head_state.gas_limit = 10 ** 12

    # deploy valmgr and its prerequisite contracts and transactions
    x = t.ABIContract(c, get_valmgr_ct(), get_valmgr_addr())

    # test deposit: fails when msg.value != DEPOSIT_SIZE
    with pytest.raises(t.TransactionFailed):
        # gas == GASLIMIT
        x.deposit(k0_valcode_addr, k0_valcode_addr)
    # test withdraw: fails when no validator record
    assert not x.withdraw(0, sign(WITHDRAW_HASH, t.k0))
    # test deposit: works fine
    return_addr = utils.privtoaddr(utils.sha3("return_addr"))
    assert 0 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0)
    assert 1 == x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1)
    assert x.withdraw(0, sign(WITHDRAW_HASH, t.k0))
    # test withdraw: see if the money is returned
    assert c.head_state.get_balance(return_addr) == DEPOSIT_SIZE
    # test deposit: make use of empty slots
    assert 0 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0)
    assert x.withdraw(1, sign(WITHDRAW_HASH, t.k1))
    # test deposit: working fine in the edge condition
    assert 1 == x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1)
    # test deposit: fails when valcode_addr is deposited before
    with pytest.raises(t.TransactionFailed):
        x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1)
    # test withdraw: fails when the signature is not corret
    assert not x.withdraw(1, sign(WITHDRAW_HASH, t.k0))

    # test sample: correctly sample the only one validator
    assert x.withdraw(0, sign(WITHDRAW_HASH, t.k0))
    assert x.sample(0) == hex(utils.big_endian_to_int(k1_valcode_addr))
    # test sample: sample returns zero_addr (i.e. 0x00) when there is no depositing validator
    assert x.withdraw(1, sign(WITHDRAW_HASH, t.k1))
    assert x.sample(0) == "0x0000000000000000000000000000000000000000"

    def get_colhdr(shard_id, parent_collation_hash, collation_coinbase=t.a0):
        period_length = 5
        expected_period_number = num_blocks // period_length
        b = c.chain.get_block_by_number(expected_period_number * period_length - 1)
        period_start_prevhash = b.header.hash
        tx_list_root = b"tx_list " * 4
        post_state_root = b"post_sta" * 4
        receipt_root = b"receipt " * 4
        sighash = utils.sha3(
            rlp.encode([
                shard_id, expected_period_number, period_start_prevhash,
                parent_collation_hash, tx_list_root, collation_coinbase,
                post_state_root, receipt_root
            ])
        )
        sig = sign(sighash, t.k0)
        return rlp.encode([
            shard_id, expected_period_number, period_start_prevhash,
            parent_collation_hash, tx_list_root, collation_coinbase,
            post_state_root, receipt_root, sig
        ])

    header_logs = []
    add_header_topic = utils.big_endian_to_int(utils.sha3("add_header()"))

    def header_event_watcher(log):
        header_logs, add_header_topic
        # print the last log and store the recent received one
        if log.topics[0] == add_header_topic:
            # print(log.data)
            header_logs.append(log.data)
            if len(header_logs) > 1:
                last_log = header_logs.pop(0)
                # [num, num, bytes32, bytes32, bytes32, address, bytes32, bytes32, bytes]
                # use sedes to prevent integer 0 from being decoded as b''
                sedes = List([utils.big_endian_int, utils.big_endian_int, utils.hash32, utils.hash32, utils.hash32, utils.address, utils.hash32, utils.hash32, binary])
                values = rlp.decode(last_log, sedes)
                print("add_header: shard_id={}, expected_period_number={}, header_hash={}, parent_header_hash={}".format(values[0], values[1], utils.sha3(last_log), values[3]))

    c.head_state.log_listeners.append(header_event_watcher)

    shard_id = 0
    shard0_genesis_colhdr_hash = utils.encode_int32(0)

    # test get_shard_head: returns genesis_colhdr_hash when there is no new header
    assert x.get_shard_head() == shard0_genesis_colhdr_hash

    h1 = get_colhdr(shard_id, shard0_genesis_colhdr_hash)
    h1_hash = utils.sha3(h1)
    # test add_header: fails when there is no collator in this period
    assert not x.add_header(h1)
    assert 1 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0)
    # test add_header: works normally with parent_collation_hash == GENESIS
    assert x.add_header(h1)
    # test add_header: fails when the header is added before
    with pytest.raises(t.TransactionFailed):
        h1 = get_colhdr(shard_id, shard0_genesis_colhdr_hash)
        x.add_header(h1)
    # test add_header: fails when the parent_collation_hash is not added before
    with pytest.raises(t.TransactionFailed):
        h2 = get_colhdr(shard_id, utils.sha3("123"))
        x.add_header(h2)
    # test add_header: the log is generated normally
    h2 = get_colhdr(shard_id, h1_hash)
    h2_hash = utils.sha3(h2)
    assert x.add_header(h2)
    latest_log_hash = utils.sha3(header_logs[-1])
    assert h2_hash == latest_log_hash
    # test get_shard_head: get the correct head when a new header is added
    assert x.get_shard_head(0) == h2_hash
    # test get_shard_head: get the correct head when a fork happened
    h1_prime = get_colhdr(shard_id, shard0_genesis_colhdr_hash, collation_coinbase=t.a1)
    h1_prime_hash = utils.sha3(h1_prime)
    assert x.add_header(h1_prime)
    h2_prime = get_colhdr(shard_id, h1_prime_hash, collation_coinbase=t.a1)
    h2_prime_hash = utils.sha3(h2_prime)
    assert x.add_header(h2_prime)
    assert x.get_shard_head(0) == h2_hash
    h3_prime = get_colhdr(shard_id, h2_prime_hash, collation_coinbase=t.a1)
    h3_prime_hash = utils.sha3(h3_prime)
    assert x.add_header(h3_prime)
    assert x.get_shard_head(0) == h3_prime_hash
    '''
    # test get_ancestor: h3_prime's height is too low so and it doesn't have a
    #                    10000th ancestor. So it should fail.
    with pytest.raises(t.TransactionFailed):
        ancestor_10000th_hash = x.get_ancestor(shard_id, h3_prime_hash)
    # test get_ancestor:
    # TODO: figure out a better test instead of adding headers one by one.
    #       This test takes few minutes. For now, you can adjust the `kth_ancestor`
    #       to a smaller number here, and the same number of iterations of the `for`
    #       loop in `get_ancestor` in the validator_manager contract.
    current_height = 3 # h3_prime
    kth_ancestor = 10000
    current_colhdr_hash = h3_prime_hash
    # add (kth_ancestor - current_height) headers to get the genesis as the ancestor
    for i in range(kth_ancestor - current_height):
        current_colhdr = get_colhdr(shard_id, current_colhdr_hash, collation_coinbase=t.a1)
        assert x.add_header(current_colhdr)
        current_colhdr_hash = utils.sha3(current_colhdr)
    assert x.get_ancestor(shard_id, current_colhdr_hash) == shard0_genesis_colhdr_hash
    '''

    # test tx_to_shard: add request tx and get the receipt id
    to_addr = utils.privtoaddr(utils.sha3("to_addr"))
    startgas = 100000
    gasprice = 1
    receipt_id0 = x.tx_to_shard(to_addr, 0, startgas, gasprice, b'', sender=t.k0, value=100)
    assert 0 == receipt_id0
    # test tx_to_shard: see if receipt_id is incrementing when called
    # multiple times
    receipt_id1 = x.tx_to_shard(to_addr, 0, startgas, gasprice, b'', sender=t.k1, value=101)
    assert 1 == receipt_id1
    assert 101 == x.get_receipts__value(receipt_id1)

    # test update_gasprice: fails when msg.sender doesn't match
    with pytest.raises(t.TransactionFailed):
        x.update_gasprice(receipt_id1, 2, sender=t.k0)
    # test update_gasprice: see if the gasprice updated successfully
    assert x.update_gasprice(receipt_id1, 2, sender=t.k1)
    assert 2 == x.get_receipts__tx_gasprice(receipt_id1)

    print(utils.checksum_encode(get_valmgr_addr()))