def test_apply_collation_wrong_root():
    """Test apply_collation with wrong roots in header
    test verify_execution_results
    """
    shard_id = 1
    t = chain(shard_id)

    # test 1 - arrange
    state = t.chain.shards[shard_id].state
    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    # post_state_root
    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    period_start_prevblock = t.chain.get_block(
        collation.header.period_start_prevhash)
    # Set wrong root
    collation.header.post_state_root = trie.BLANK_ROOT
    with pytest.raises(ValueError):
        collator.apply_collation(state, collation, period_start_prevblock)

    # test 2 - arrange
    state = t.chain.shards[shard_id].state
    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    # receipts_root
    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    period_start_prevblock = t.chain.get_block(
        collation.header.period_start_prevhash)
    # Set wrong root
    collation.header.receipts_root = trie.BLANK_ROOT
    with pytest.raises(ValueError):
        collator.apply_collation(state, collation, period_start_prevblock)

    # test 3 - arrange
    state = t.chain.shards[shard_id].state
    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    # receipts_root
    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    period_start_prevblock = t.chain.get_block(
        collation.header.period_start_prevhash)
    # Set wrong root
    collation.header.tx_list_root = trie.BLANK_ROOT
    with pytest.raises(ValueError):
        collator.apply_collation(state, collation, period_start_prevblock)
def test_apply_collation():
    """Apply collation to ShardChain
    """
    shard_id = 1
    t = chain(shard_id)

    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    state = t.chain.shards[shard_id].state
    prev_state_root = state.trie.root_hash
    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    period_start_prevblock = t.chain.get_block(
        collation.header.period_start_prevhash)

    collator.apply_collation(state, collation, period_start_prevblock)

    assert state.trie.root_hash != prev_state_root
    assert collation.header.post_state_root == state.trie.root_hash
    assert collation.header.post_state_root == t.chain.shards[
        shard_id].state.trie.root_hash
def test_create_collation_with_txs():
    """Test create_collation with transactions
    """
    shard_id = 1
    t = chain(shard_id)

    parent_collation_hash = t.chain.shards[shard_id].head_hash
    expected_period_number = t.chain.get_expected_period_number()

    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    collation = collator.create_collation(t.chain,
                                          shard_id,
                                          parent_collation_hash,
                                          expected_period_number,
                                          coinbase=tester.a0,
                                          key=tester.k0,
                                          txqueue=txqueue)
    assert collation.transaction_count == 2
def test_create_collation_empty_txqueue():
    """Test create_collation without transactions
    """
    shard_id = 1
    t = chain(shard_id)

    parent_collation_hash = t.chain.shards[shard_id].head_hash
    expected_period_number = t.chain.get_expected_period_number()

    txqueue = TransactionQueue()
    collation = collator.create_collation(t.chain,
                                          shard_id,
                                          parent_collation_hash,
                                          expected_period_number,
                                          coinbase=tester.a1,
                                          key=tester.k1,
                                          txqueue=txqueue)

    assert collation.transaction_count == 0
    assert collation.header.coinbase == tester.a1

    # sign error
    with pytest.raises(TypeError):
        collation = collator.create_collation(t.chain,
                                              shard_id,
                                              parent_collation_hash,
                                              expected_period_number,
                                              coinbase=tester.a1,
                                              key=123,
                                              txqueue=txqueue)
Exemple #5
0
def mine_on_chain(chain,
                  parent=None,
                  transactions=[],
                  coinbase=None,
                  timestamp=None):
    """Mine the next block on a chain.

    The newly mined block will be considered to be the head of the chain,
    regardless of its total difficulty.

    :param parent: the parent of the block to mine, or `None` to use the
                   current chain head
    :param transactions: a list of transactions to include in the new block
    :param coinbase: optional coinbase to replace ``chain.coinbase``
    """
    txqueue = TransactionQueue()
    for t in transactions:
        txqueue.add_transaction(t)
    parent_timestamp = parent.timestamp if parent else chain.state.timestamp
    hc, _ = meta.make_head_candidate(chain, txqueue, parent, timestamp
                                     or parent_timestamp + 1, coinbase
                                     or '\x00' * 20)
    assert hc.difficulty == 1
    m = ethpow.Miner(hc)
    rounds = 100
    nonce = 0
    while True:
        b = m.mine(rounds=rounds, start_nonce=nonce)
        if b:
            break
        nonce += rounds
    assert chain.add_block(b)
    return b
Exemple #6
0
 def __init__(self, app):
     super(ChainServiceMock, self).__init__(app)
     self.on_new_head_cbs = []
     self.transaction_queue = TransactionQueue()
     self.is_syncing = False
     self.mined_block = None
     self.block_mined_event = Event()
     self.head_candidate = Block(BlockHeader(difficulty=DIFFICULTY),
                                 db=DB())
def test_verify_collation_header():
    shard_id = 1
    t = chain(shard_id)

    parent_collation_hash = t.chain.shards[shard_id].head_hash
    expected_period_number = t.chain.get_expected_period_number()

    txqueue = TransactionQueue()
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    collation = collator.create_collation(t.chain,
                                          shard_id,
                                          parent_collation_hash,
                                          expected_period_number,
                                          coinbase=tester.a0,
                                          key=tester.k0,
                                          txqueue=txqueue)

    # Verify collation header
    assert collator.verify_collation_header(t.chain, collation.header)

    # Bad collation header 1
    collation = collator.create_collation(t.chain,
                                          shard_id,
                                          parent_collation_hash,
                                          expected_period_number,
                                          coinbase=tester.a1,
                                          key=tester.k1,
                                          txqueue=txqueue)
    collation.header.shard_id = -1
    with pytest.raises(ValueError):
        collator.verify_collation_header(t.chain, collation.header)

    # Bad collation header 2 - call_msg_add_header error
    collation = collator.create_collation(t.chain,
                                          shard_id,
                                          parent_collation_hash,
                                          expected_period_number,
                                          coinbase=tester.a1,
                                          key=tester.k1,
                                          txqueue=txqueue)
    collation.header.sig = utils.sha3('hello')
    with pytest.raises(ValueError):
        collator.verify_collation_header(t.chain, collation.header)
def test_transaction():
    """Test create and apply collation with transactions
    """
    shard_id = 1
    t = chain(shard_id)
    log.info('head state: {}'.format(
        encode_hex(t.chain.shards[shard_id].state.trie.root_hash)))

    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))

    # Prepare txqueue
    txqueue = TransactionQueue()
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    log.debug('collation: {}, transaction_count:{}'.format(
        collation.to_dict(), collation.transaction_count))

    period_start_prevblock = t.chain.get_block(
        collation.header.period_start_prevhash)
    log.debug('period_start_prevblock: {}'.format(
        encode_hex(period_start_prevblock.header.hash)))
    t.chain.shards[shard_id].add_collation(collation, period_start_prevblock,
                                           t.chain.handle_ignored_collation)

    state = t.chain.shards[shard_id].mk_poststate_of_collation_hash(
        collation.header.hash)

    # Check to addesss received value
    assert state.get_balance(tester.a4) == 1000030000000000000000
    # Check incentives
    assert state.get_balance(tester.a1) == 1000002000000000000000

    # mk_poststate_of_collation_hash error
    with pytest.raises(Exception):
        state = t.chain.shards[shard_id].mk_poststate_of_collation_hash(
            b'1234')
def test_validate_transaction_tree():
    """Test validate_transaction_tree(collation)
    """
    t = chain(shard_id)
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))
    txqueue = TransactionQueue()
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    collation = t.generate_collation(shard_id=1,
                                     coinbase=tester.a1,
                                     key=tester.k1,
                                     txqueue=txqueue)
    assert state_transition.validate_transaction_tree(collation)

    collation.header.tx_list_root = trie.BLANK_ROOT
    with pytest.raises(ValueError):
        state_transition.validate_transaction_tree(collation)
Exemple #10
0
 def __init__(self, genesis, key, network, env, time_offset=5):
     # Create a chain object
     self.chain = Chain(genesis, env=env)
     # Create a transaction queue
     self.txqueue = TransactionQueue()
     # Use the validator's time as the chain's time
     self.chain.time = lambda: self.get_timestamp()
     # My private key
     self.key = key
     # My address
     self.address = privtoaddr(key)
     # My randao
     self.randao = RandaoManager(sha3(self.key))
     # Pointer to the test p2p network
     self.network = network
     # Record of objects already received and processed
     self.received_objects = {}
     # The minimum eligible timestamp given a particular number of skips
     self.next_skip_count = 0
     self.next_skip_timestamp = 0
     # Is this validator active?
     self.active = False
     # Code that verifies signatures from this validator
     self.validation_code = generate_validation_code(privtoaddr(key))
     # Validation code hash
     self.vchash = sha3(self.validation_code)
     # Parents that this validator has already built a block on
     self.used_parents = {}
     # This validator's clock offset (for testing purposes)
     self.time_offset = random.randrange(time_offset) - (time_offset // 2)
     # Determine the epoch length
     self.epoch_length = self.call_casper('getEpochLength')
     # My minimum gas price
     self.mingasprice = 20 * 10**9
     # Give this validator a unique ID
     self.id = len(ids)
     ids.append(self.id)
     self.update_activity_status()
     self.cached_head = self.chain.head_hash
def test_add_transactions():
    """Test add_transactions(state, collation, txqueue, min_gasprice=0)
    """
    t = chain(shard_id)
    tx1 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(0.03 * utils.denoms.ether))
    tx2 = t.generate_shard_tx(shard_id, tester.k3, tester.a5,
                              int(0.03 * utils.denoms.ether))
    txqueue = TransactionQueue()
    txqueue.add_transaction(tx1)
    txqueue.add_transaction(tx2)

    coinbase = tester.a1
    state = t.chain.shards[shard_id].state.ephemeral_clone()
    collation = state_transition.mk_collation_from_prevstate(
        t.chain.shards[shard_id], state, coinbase)

    state_transition.add_transactions(state,
                                      collation,
                                      txqueue,
                                      shard_id,
                                      mainchain_state=t.head_state)
    assert collation.transaction_count == 2
    assert state.get_balance(tester.a4) == 1000 * utils.denoms.ether + int(
        0.03 * utils.denoms.ether)

    # InsufficientBalance -> don't include this transaction
    tx3 = t.generate_shard_tx(shard_id, tester.k2, tester.a4,
                              int(100000000000 * utils.denoms.ether))
    txqueue.add_transaction(tx3)
    state_transition.add_transactions(state,
                                      collation,
                                      txqueue,
                                      shard_id,
                                      mainchain_state=t.head_state)
    assert collation.transaction_count == 2
Exemple #12
0
 def __init__(self, key, genesis, network, valcode_addr=None, mining=False):
     self.key = key
     self.coinbase = utils.privtoaddr(self.key)
     self.chain = chain.Chain(genesis=genesis,
                              reset_genesis=True,
                              coinbase=self.coinbase,
                              new_head_cb=self._on_new_head)
     self.mining = mining
     self.nonce = self.chain.state.get_nonce(self.coinbase)
     self.valcode_tx = None
     self.deposit_tx = None
     self.valcode_addr = valcode_addr
     self.prepares = dict()
     self.prev_prepare_epoch = 0
     self.prev_commit_epoch = 0
     self.epoch_length = self.chain.env.config['EPOCH_LENGTH']
     # When the transaction_queue is modified, we must set
     # self._head_candidate_needs_updating to True in order to force the
     # head candidate to be updated.
     self.transaction_queue = TransactionQueue()
     self._head_candidate_needs_updating = True
     # Add validator to the network
     self.network = network
     self.network.join(self)
Exemple #13
0
def make_block(chain, key, randao, vchash, skips):
    h, _ = make_head_candidate(chain, TransactionQueue(), timestamp=get_timestamp(chain, skips))
    return sign_block(h, key, randao.get_parent(call_casper(chain.state, 'getRandao', [vchash])), vchash, skips)
Exemple #14
0
    def __init__(self, app):
        self.config = app.config
        sce = self.config['eth']
        if int(sce['pruning']) >= 0:
            self.db = RefcountDB(app.services.db)
            if "I am not pruning" in self.db.db:
                raise RuntimeError(
                    "The database in '{}' was initialized as non-pruning. "
                    "Can not enable pruning now.".format(
                        self.config['data_dir']))
            self.db.ttl = int(sce['pruning'])
            self.db.db.put("I am pruning", "1")
        else:
            self.db = app.services.db
            if "I am pruning" in self.db:
                raise RuntimeError(
                    "The database in '{}' was initialized as pruning. "
                    "Can not disable pruning now".format(
                        self.config['data_dir']))
            self.db.put("I am not pruning", "1")

        if 'network_id' in self.db:
            db_network_id = self.db.get(b'network_id')
            if db_network_id != to_string(sce['network_id']):
                raise RuntimeError(
                    "The database in '{}' was initialized with network id {} and can not be used "
                    "when connecting to network id {}. Please choose a different data directory."
                    .format(self.config['data_dir'], db_network_id,
                            sce['network_id']))

        else:
            self.db.put(b'network_id', to_string(sce['network_id']))
            self.db.commit()

        assert self.db is not None

        super(ChainService, self).__init__(app)
        log.info('initializing chain')
        coinbase = app.services.accounts.coinbase
        env = Env(self.db, sce['block'])

        genesis_data = sce.get('genesis_data', {})
        if not genesis_data:
            genesis_data = mk_genesis_data(env)
        self.chain = Chain(env=env,
                           genesis=genesis_data,
                           coinbase=coinbase,
                           new_head_cb=self._on_new_head)
        header = self.chain.state.prev_headers[0]
        log.info('chain at', number=header.number)
        if 'genesis_hash' in sce:
            assert sce['genesis_hash'] == self.chain.genesis.hex_hash, \
                "Genesis hash mismatch.\n  Expected: %s\n  Got: %s" % (
                    sce['genesis_hash'], self.chain.genesis.hex_hash)

        self.dao_challenges = dict()
        self.synchronizer = Synchronizer(self, force_sync=None)

        self.block_queue = Queue(maxsize=self.block_queue_size)
        # When the transaction_queue is modified, we must set
        # self._head_candidate_needs_updating to True in order to force the
        # head candidate to be updated.
        self.transaction_queue = TransactionQueue()
        self._head_candidate_needs_updating = True
        # Initialize a new head candidate.
        _ = self.head_candidate
        self.min_gasprice = 20 * 10**9  # TODO: better be an option to validator service?
        self.add_blocks_lock = False
        self.add_transaction_lock = gevent.lock.Semaphore()
        self.broadcast_filter = DuplicatesFilter()
        self.on_new_head_cbs = []
        self.newblock_processing_times = deque(maxlen=1000)
        gevent.spawn_later(self.process_time_queue_period,
                           self.process_time_queue)