def create_reward_test_blockchain_database():
    testdb = MemoryDB()

    chain = MainnetChain(testdb, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), GENESIS_PRIVATE_KEY)
    coin_mature_time = chain.get_vm(timestamp=Timestamp(int(time.time()))).consensus_db.coin_mature_time_for_staking
    min_time_between_blocks = chain.get_vm(timestamp=Timestamp(int(time.time()))).min_time_between_blocks
    required_stake_for_reward_type_2_proof = chain.get_consensus_db(timestamp=Timestamp(int(time.time()))).required_stake_for_reward_type_2_proof


    now = int(time.time())
    start = now - max((coin_mature_time * 2), (min_time_between_blocks * 20))
    key_balance_dict = {}
    for i in range(10):
        key_balance_dict[private_keys[i]] = (
        required_stake_for_reward_type_2_proof, start + min_time_between_blocks * i)

    create_dev_fixed_blockchain_database(testdb, key_balance_dict)
    return testdb
def test_erc_20_smart_contract_deploy_system():

    # testdb = LevelDB('/home/tommy/.local/share/helios/instance_test/mainnet/chain/full/')
    # testdb = JournalDB(testdb)
    testdb = MemoryDB()
    chain = TestnetChain(
        testdb, TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
        TESTNET_GENESIS_PRIVATE_KEY)
    coin_mature_time = chain.get_vm(timestamp=Timestamp(int(
        time.time()))).consensus_db.coin_mature_time_for_staking

    now = int(time.time())
    key_balance_dict = {
        private_keys[0]: (1000000000000, now - coin_mature_time * 10 - 100)
    }
    create_dev_fixed_blockchain_database(testdb, key_balance_dict)

    chain = TestnetChain(
        testdb, TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
        TESTNET_GENESIS_PRIVATE_KEY)

    min_time_between_blocks = chain.get_vm(
        timestamp=Timestamp(int(time.time()))).min_time_between_blocks
    for private_key, balance_time in key_balance_dict.items():
        assert (chain.get_vm().state.account_db.get_balance(
            private_key.public_key.to_canonical_address()) == balance_time[0])

    SOLIDITY_SRC_FILE = 'contract_data/erc20.sol'
    EXPECTED_TOTAL_SUPPLY = 10000000000000000000000

    #compiled_sol = compile_files([SOLIDITY_SRC_FILE])

    compiled_sol = load_compiled_sol_dict('contract_data/erc20_compiled.pkl')

    contract_interface = compiled_sol['{}:SimpleToken'.format(
        SOLIDITY_SRC_FILE)]

    w3 = Web3()

    SimpleToken = w3.eth.contract(abi=contract_interface['abi'],
                                  bytecode=contract_interface['bin'])

    # Build transaction to deploy the contract
    w3_tx1 = SimpleToken.constructor().buildTransaction(W3_TX_DEFAULTS)

    max_gas = 20000000

    chain.create_and_sign_transaction_for_queue_block(
        gas_price=0x01,
        gas=max_gas,
        to=CREATE_CONTRACT_ADDRESS,
        value=0,
        data=decode_hex(w3_tx1['data']),
        v=0,
        r=0,
        s=0)

    #time.sleep(1)
    print("deploying smart contract")

    initial_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    imported_block = chain.import_current_queue_block()
    final_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    gas_used = to_int(
        chain.chaindb.get_receipts(imported_block.header, Receipt)[0].gas_used)
    assert ((initial_balance - final_balance) == gas_used)

    print(TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    print(
        generate_contract_address(
            TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
            imported_block.transactions[0].nonce))
    print(
        chain.chaindb.get_receipts(imported_block.header,
                                   Receipt)[0].logs[0].address)

    #contractAddress

    print("Used the correct amount of gas.")

    #now we need to add the block to the smart contract
    list_of_smart_contracts = chain.get_vm(
    ).state.account_db.get_smart_contracts_with_pending_transactions()
    deployed_contract_address = list_of_smart_contracts[0]
    print(list_of_smart_contracts)

    chain = TestnetChain(testdb, deployed_contract_address, private_keys[0])

    chain.populate_queue_block_with_receive_tx()
    imported_block = chain.import_current_queue_block()

    list_of_smart_contracts = chain.get_vm(
    ).state.account_db.get_smart_contracts_with_pending_transactions()
    print(list_of_smart_contracts)

    #lets make sure it didn't create a refund transaction for the initial sender.
    print(chain.get_vm().state.account_db.has_receivable_transactions(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address()))

    # print('ASDASD')
    # print(chain.chaindb.get_receipts(imported_block.header, Receipt)[0].logs[0].data)

    #
    # Interacting with deployed smart contract step 1) add send transaction
    #
    chain = TestnetChain(
        testdb, TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
        TESTNET_GENESIS_PRIVATE_KEY)

    simple_token = w3.eth.contract(
        address=Web3.toChecksumAddress(deployed_contract_address),
        abi=contract_interface['abi'],
    )

    w3_tx2 = simple_token.functions.totalSupply().buildTransaction(
        W3_TX_DEFAULTS)

    chain.create_and_sign_transaction_for_queue_block(
        gas_price=0x01,
        gas=max_gas,
        to=deployed_contract_address,
        value=0,
        data=decode_hex(w3_tx2['data']),
        v=0,
        r=0,
        s=0)

    #lets make sure it subtracts the entire max gas
    initial_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())

    print("waiting {} seconds before importing next block".format(
        min_time_between_blocks))
    time.sleep(min_time_between_blocks)
    chain.import_current_queue_block()
    final_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    assert ((initial_balance - final_balance) == max_gas)

    #
    # Interacting with deployed smart contract step 2) add receive transaction to smart contract chain
    #

    chain = TestnetChain(testdb, deployed_contract_address, private_keys[0])
    chain.populate_queue_block_with_receive_tx()

    receivable_transactions = chain.get_vm(
    ).state.account_db.get_receivable_transactions(deployed_contract_address)
    print('receivable_transactions before imported into contract chain')
    print(receivable_transactions)

    print("waiting {} seconds before importing next block".format(
        min_time_between_blocks))
    time.sleep(min_time_between_blocks)
    imported_block = chain.import_current_queue_block()

    receipt = chain.chaindb.get_receipts(imported_block.header, Receipt)[0]
    receipt_dict = format_receipt_for_web3_to_extract_events(
        receipt, imported_block.receive_transactions[0].hash, chain)

    rich_logs = simple_token.events.Print().processReceipt(receipt_dict)
    print(rich_logs[0]['args'])
    print('a')

    #now lets look at the reciept to see the result
    assert (to_int(
        chain.chaindb.get_receipts(
            imported_block.header,
            Receipt)[0].logs[0].data) == EXPECTED_TOTAL_SUPPLY)
    print("Total supply call gave expected result!")
    gas_used = to_int(
        chain.chaindb.get_receipts(imported_block.header, Receipt)[0].gas_used)

    #
    # Interacting with deployed smart contract step 3) Receiving refund of extra gas that wasn't used in the computation
    #
    initial_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    chain = TestnetChain(
        testdb, TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
        TESTNET_GENESIS_PRIVATE_KEY)

    #
    # Make sure the receive transaction is no longer in the account receivable
    #
    receivable_transactions = chain.get_vm(
    ).state.account_db.get_receivable_transactions(deployed_contract_address)
    print('receivable_transactions after imported into contract chain')
    print(receivable_transactions)

    chain.populate_queue_block_with_receive_tx()

    print("waiting {} seconds before importing next block".format(
        min_time_between_blocks))
    time.sleep(min_time_between_blocks)
    imported_block = chain.import_current_queue_block()
    final_balance = chain.get_vm().state.account_db.get_balance(
        TESTNET_GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    assert ((final_balance - initial_balance) == (max_gas - gas_used))
    print("Refunded gas is the expected amount.")
def test_invalid_proofs_not_enough_stake():
    testdb = MemoryDB()

    chain = MainnetChain(testdb, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), GENESIS_PRIVATE_KEY)
    coin_mature_time = chain.get_vm(timestamp=Timestamp(int(time.time()))).consensus_db.coin_mature_time_for_staking
    min_time_between_blocks = chain.get_vm(timestamp=Timestamp(int(time.time()))).min_time_between_blocks
    now = int(time.time())
    start = now - max((coin_mature_time * 2), (min_time_between_blocks * 20))
    key_balance_dict = {
        private_keys[0]: (to_wei(1, 'ether'), start),
        private_keys[1]: (to_wei(1, 'ether'), start + min_time_between_blocks * 1),
        private_keys[2]: (to_wei(1, 'ether'), start + min_time_between_blocks * 2),
        private_keys[3]: (to_wei(1, 'ether'), start + min_time_between_blocks * 3),
        private_keys[4]: (to_wei(1, 'ether'), start + min_time_between_blocks * 4),
        private_keys[5]: (to_wei(1, 'ether'), start + min_time_between_blocks * 5),
        private_keys[6]: (to_wei(1, 'ether'), start + min_time_between_blocks * 6),
        private_keys[7]: (to_wei(1, 'ether'), start + min_time_between_blocks * 7),
        private_keys[8]: (to_wei(1, 'ether'), start + min_time_between_blocks * 8),
        private_keys[9]: (to_wei(1, 'ether'), now - coin_mature_time + 1),  # immature
    }
    create_dev_fixed_blockchain_database(testdb, key_balance_dict)

    chain = MainnetChain(testdb, private_keys[0].public_key.to_canonical_address(), private_keys[0])

    node_staking_scores = []

    # First score/proof with timestamp far in future
    current_private_key = private_keys[1]
    node_staking_score = NodeStakingScore(
        recipient_node_wallet_address=private_keys[0].public_key.to_canonical_address(),
        score=int(1000000),
        since_block_number=0,
        timestamp=int(time.time())-60*10,
        head_hash_of_sender_chain=chain.chaindb.get_canonical_head_hash(
            current_private_key.public_key.to_canonical_address()),
        v=0,
        r=0,
        s=0,
    )
    signed_node_staking_score = node_staking_score.get_signed(current_private_key, MAINNET_NETWORK_ID)
    node_staking_scores.append(signed_node_staking_score)

    score = 100000
    for i in range(2, 10):
        # Second score/proof is from instance 1
        current_private_key = private_keys[i]
        node_staking_score = NodeStakingScore(
            recipient_node_wallet_address=private_keys[0].public_key.to_canonical_address(),
            score=int(score-i),
            since_block_number=1,
            timestamp=int(time.time()),
            head_hash_of_sender_chain=chain.chaindb.get_canonical_head_hash(
                current_private_key.public_key.to_canonical_address()),
            v=0,
            r=0,
            s=0,
            )
        signed_node_staking_score = node_staking_score.get_signed(current_private_key, MAINNET_NETWORK_ID)
        node_staking_scores.append(signed_node_staking_score)

    # Now we try to import the reward block with instance 0
    reward_chain = MainnetChain(testdb, private_keys[0].public_key.to_canonical_address(), private_keys[0])

    with pytest.raises(NotEnoughProofsOrStakeForRewardType2Proof):
        reward_chain.import_current_queue_block_with_reward(node_staking_scores)