require 'ciri'
require 'ciri/pow_chain/transaction'
require 'ciri/forks/byzantium'
require 'ciri/key'
require 'ciri/state'
require 'ciri/evm'
require 'ciri/evm/block_info'
require 'ciri/db/backend/memory'
require 'ciri/utils/logger'
require 'ciri/utils'

include Ciri

Utils::Logger.setup(level: :info)

# bytecode of ballot contract, copy from remix example
BALLOT_BYTECODE = Utils.dehex "608060405234801561001057600080fd5b50604051602080610487833981016040908152905160008054600160a060020a0319163317808255600160a060020a03168152600160208190529290209190915560ff8116610060600282610067565b50506100b1565b81548183558181111561008b5760008381526020902061008b918101908301610090565b505050565b6100ae91905b808211156100aa5760008155600101610096565b5090565b90565b6103c7806100c06000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416635c19a95c8114610066578063609ff1bd146100895780639e7b8d61146100b4578063b3f98adc146100d5575b600080fd5b34801561007257600080fd5b50610087600160a060020a03600435166100f0565b005b34801561009557600080fd5b5061009e610250565b6040805160ff9092168252519081900360200190f35b3480156100c057600080fd5b50610087600160a060020a03600435166102bb565b3480156100e157600080fd5b5061008760ff6004351661031b565b33600090815260016020819052604082209081015490919060ff16156101155761024b565b5b600160a060020a0383811660009081526001602081905260409091200154620100009004161580159061016d5750600160a060020a0383811660009081526001602081905260409091200154620100009004163314155b1561019f57600160a060020a039283166000908152600160208190526040909120015462010000900490921691610116565b600160a060020a0383163314156101b55761024b565b506001818101805460ff1916821775ffffffffffffffffffffffffffffffffffffffff0000191662010000600160a060020a0386169081029190911790915560009081526020829052604090209081015460ff16156102435781546001820154600280549091610100900460ff1690811061022c57fe5b60009182526020909120018054909101905561024b565b815481540181555b505050565b600080805b60025460ff821610156102b6578160028260ff1681548110151561027557fe5b906000526020600020016000015411156102ae576002805460ff831690811061029a57fe5b906000526020600020016000015491508092505b600101610255565b505090565b600054600160a060020a0316331415806102f15750600160a060020a0381166000908152600160208190526040909120015460ff165b156102fb57610318565b600160a060020a0381166000908152600160208190526040909120555b50565b3360009081526001602081905260409091209081015460ff1680610344575060025460ff831610155b1561034e57610397565b6001818101805460ff191690911761ff00191661010060ff85169081029190911790915581546002805491929091811061038457fe5b6000918252602090912001805490910190555b50505600a165627a7a723058200864fb02ff362bbc06e105162a9fcbfe289feff2354dbe84cf794f1fb2ec38d60029"
# generate a contract creation transaction
priv_key = Key.random
transaction = POWChain::Transaction.new(
    nonce: 1,
    gas_price: 10,
    gas_limit: 3000000,
    to: '',
    value: 0,
    data: BALLOT_BYTECODE
)
transaction.sign_with_key!(priv_key)

# prepare some eth to sender account
state = State.new(DB::Backend::Memory.new)
state.add_balance(transaction.sender, 10 ** 18)

block_info = EVM::BlockInfo.new(
    coinbase: "\x00".b * 20,
)

evm = EVM.new(state: state, fork_schema: Ciri::Forks::Byzantium::Schema.new)
result = evm.execute_transaction(transaction, block_info: block_info)

puts "Ballot contract transaction\n---------"
puts "sender:#{Utils.hex transaction.sender}\n-> send #{transaction.value} value to\nto:#{Utils.hex transaction.to}\ndata(#{transaction.data.size} bytes)"

puts "\nEVM executing ->\n\n"

puts "Execution result\n---------"
if result.status == 0
  puts "Transaction failed"
  exit 1
end

material = RLP.encode_simple([transaction.sender.to_s, transaction.nonce])
contract_address = Utils.keccak(material)[-20..-1]

puts "Transaction success!!"
puts "Gas Used: #{result.gas_used}"
puts "State root: #{Utils.hex result.state_root}"
puts "Contract created at: #{Utils.hex contract_address}"
puts "Contract data(#{result.output.size} bytes)"
