github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/evm.go (about) 1 package core 2 3 import ( 4 "math/big" 5 6 "github.com/quickchainproject/quickchain/common" 7 "github.com/quickchainproject/quickchain/consensus" 8 "github.com/quickchainproject/quickchain/core/types" 9 "github.com/quickchainproject/quickchain/core/vm" 10 ) 11 12 // ChainContext supports retrieving headers and consensus parameters from the 13 // current blockchain to be used during transaction processing. 14 type ChainContext interface { 15 // Engine retrieves the chain's consensus engine. 16 Engine() consensus.Engine 17 18 // GetHeader returns the hash corresponding to their hash. 19 GetHeader(common.Hash, uint64) *types.Header 20 } 21 22 // NewEVMContext creates a new context for use in the EVM. 23 func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context { 24 // If we don't have an explicit author (i.e. not mining), extract from the header 25 var beneficiary common.Address 26 if author == nil { 27 beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation 28 } else { 29 beneficiary = *author 30 } 31 return vm.Context{ 32 CanTransfer: CanTransfer, 33 Transfer: Transfer, 34 GetHash: GetHashFn(header, chain), 35 Origin: msg.From(), 36 Coinbase: beneficiary, 37 BlockNumber: new(big.Int).Set(header.Number), 38 Time: new(big.Int).Set(header.Time), 39 Difficulty: new(big.Int).Set(header.Difficulty), 40 GasLimit: header.GasLimit, 41 GasPrice: new(big.Int).Set(msg.GasPrice()), 42 } 43 } 44 45 // GetHashFn returns a GetHashFunc which retrieves header hashes by number 46 func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { 47 var cache map[uint64]common.Hash 48 49 return func(n uint64) common.Hash { 50 // If there's no hash cache yet, make one 51 if cache == nil { 52 cache = map[uint64]common.Hash{ 53 ref.Number.Uint64() - 1: ref.ParentHash, 54 } 55 } 56 // Try to fulfill the request from the cache 57 if hash, ok := cache[n]; ok { 58 return hash 59 } 60 // Not cached, iterate the blocks and cache the hashes 61 for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { 62 cache[header.Number.Uint64()-1] = header.ParentHash 63 if n == header.Number.Uint64()-1 { 64 return header.ParentHash 65 } 66 } 67 return common.Hash{} 68 } 69 } 70 71 // CanTransfer checks wether there are enough funds in the address' account to make a transfer. 72 // This does not take the necessary gas in to account to make the transfer valid. 73 func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { 74 return db.GetBalance(addr).Cmp(amount) >= 0 75 } 76 77 // Transfer subtracts amount from sender and adds amount to recipient using the given Db 78 func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { 79 db.SubBalance(sender, amount) 80 db.AddBalance(recipient, amount) 81 }