/
evm.go
71 lines (64 loc) · 2.4 KB
/
evm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package transaction
import (
"math/big"
"github.com/LemoFoundationLtd/lemochain-core/chain/types"
"github.com/LemoFoundationLtd/lemochain-core/chain/vm"
"github.com/LemoFoundationLtd/lemochain-core/common"
)
// NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(tx *types.Transaction, header *types.Header, txIndex uint, blockHash common.Hash, chain BlockLoader) vm.Context {
if (header.MinerAddress == common.Address{}) {
panic("NewEVMContext is called without author")
}
from := tx.From()
return vm.Context{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
TxIndex: txIndex,
TxHash: tx.Hash(),
BlockHash: blockHash,
Origin: from,
MinerAddress: header.MinerAddress,
BlockHeight: header.Height,
Time: header.Time,
GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(tx.GasPrice()),
}
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain BlockLoader) vm.GetHashFunc {
var cache map[uint32]common.Hash
return func(n uint32) common.Hash {
// If there's no hash cache yet, make one
if cache == nil {
// ref references the block we are building now. So we should not use its hash
cache = map[uint32]common.Hash{
ref.Height - 1: ref.ParentHash,
}
}
// Try to fulfill the request from the cache
if hash, ok := cache[n]; ok {
return hash
}
// Not cached, find the block and cache the hash
if block := chain.GetParentByHeight(n, ref.ParentHash); block != nil {
hash := block.Hash()
cache[block.Header.Height] = hash
return hash
}
return common.Hash{}
}
}
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid.
func CanTransfer(am vm.AccountManager, addr common.Address, amount *big.Int) bool {
return am.GetAccount(addr).GetBalance().Cmp(amount) >= 0
}
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(am vm.AccountManager, sender, recipient common.Address, amount *big.Int) {
senderAccount := am.GetAccount(sender)
recipientAccount := am.GetAccount(recipient)
senderAccount.SetBalance(new(big.Int).Sub(senderAccount.GetBalance(), amount))
recipientAccount.SetBalance(new(big.Int).Add(recipientAccount.GetBalance(), amount))
}