Rollup evm to geth v1.9.9 Muir Glacier (#3356)

* Rollup evm to geth v1.9.9 Muir Glacier

* fix go gen

* update intrinsic gas for istanbul

* Update statedb.Commit

* revert go gen result

* revert protobuf version

* update protobuf

* update go gen files

* set testnet epoch for evm upgrade
pull/3377/head
Rongjian Lan 4 years ago committed by GitHub
parent 1b66674f29
commit 4452b36ee4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      accounts/keystore/keystore_test.go
  2. 2
      api/proto/message/message.pb.go
  3. 2
      api/service/syncing/downloader/proto/downloader.pb.go
  4. 19
      core/rawdb/accessors_chain_test.go
  5. 7
      core/rawdb/accessors_indexes_test.go
  6. 5
      core/staking_verifier_test.go
  7. 104
      core/state/database.go
  8. 149
      core/state/dump.go
  9. 5
      core/state/managed_state_test.go
  10. 344
      core/state/state_object.go
  11. 78
      core/state/state_test.go
  12. 249
      core/state/statedb.go
  13. 337
      core/state/statedb_test.go
  14. 16
      core/state_transition.go
  15. 8
      core/tx_pool.go
  16. 33
      core/tx_pool_test.go
  17. 6
      core/types/tx_errorsink.go
  18. 30
      core/vm/common.go
  19. 197
      core/vm/contracts.go
  20. 185
      core/vm/contracts_test.go
  21. 92
      core/vm/eips.go
  22. 6
      core/vm/evm.go
  23. 18
      core/vm/gas.go
  24. 422
      core/vm/gas_table.go
  25. 96
      core/vm/gas_table_test.go
  26. 62
      core/vm/instructions.go
  27. 230
      core/vm/instructions_test.go
  28. 2
      core/vm/interface.go
  29. 101
      core/vm/interpreter.go
  30. 1438
      core/vm/jump_table.go
  31. 8
      core/vm/logger.go
  32. 4
      core/vm/memory.go
  33. 114
      core/vm/memory_table.go
  34. 18
      core/vm/opcodes.go
  35. 6
      core/vm/runtime/runtime.go
  36. 7
      core/vm/runtime/runtime_test.go
  37. 7
      core/vm/stack.go
  38. 34
      core/vm/stack_table.go
  39. 1
      core/vm/testdata/testcases_add.json
  40. 1
      core/vm/testdata/testcases_and.json
  41. 1
      core/vm/testdata/testcases_byte.json
  42. 1
      core/vm/testdata/testcases_div.json
  43. 1
      core/vm/testdata/testcases_eq.json
  44. 1
      core/vm/testdata/testcases_exp.json
  45. 1
      core/vm/testdata/testcases_gt.json
  46. 1
      core/vm/testdata/testcases_lt.json
  47. 1
      core/vm/testdata/testcases_mod.json
  48. 1
      core/vm/testdata/testcases_mul.json
  49. 1
      core/vm/testdata/testcases_or.json
  50. 1
      core/vm/testdata/testcases_sar.json
  51. 1
      core/vm/testdata/testcases_sdiv.json
  52. 1
      core/vm/testdata/testcases_sgt.json
  53. 1
      core/vm/testdata/testcases_shl.json
  54. 1
      core/vm/testdata/testcases_shr.json
  55. 1
      core/vm/testdata/testcases_signext.json
  56. 1
      core/vm/testdata/testcases_slt.json
  57. 1
      core/vm/testdata/testcases_smod.json
  58. 1
      core/vm/testdata/testcases_sub.json
  59. 1
      core/vm/testdata/testcases_xor.json
  60. 35
      go.mod
  61. 3
      hmy/bloombits.go
  62. 21
      internal/params/config.go
  63. 106
      internal/params/protocol_params.go
  64. 6
      internal/shardchain/dbfactory.go
  65. 1
      node/worker/worker.go
  66. 12
      node/worker/worker_test.go
  67. 5
      staking/slash/double-sign_test.go
  68. 2
      staking/types/messages.go
  69. 4
      test/chain/main.go
  70. 7
      test/chain/reward/main.go

@ -217,9 +217,9 @@ func tmpKeyStore(t *testing.T, encrypted bool) (string, *KeyStore) {
if err != nil {
t.Fatal(err)
}
new := NewPlaintextKeyStore
newK := NewPlaintextKeyStore
if encrypted {
new = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) }
newK = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) }
}
return d, new(d)
return d, newK(d)
}

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.23.0
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: message.proto

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.23.0
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: downloader.proto

@ -21,8 +21,9 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
@ -33,7 +34,7 @@ import (
// Tests block header storage and retrieval operations.
func TestHeaderStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
// Create a test header to move around the database and make sure it's really new
header := blockfactory.NewTestHeader().With().Number(big.NewInt(42)).Extra([]byte("test header")).Header()
@ -66,7 +67,7 @@ func TestHeaderStorage(t *testing.T) {
// Tests block body storage and retrieval operations.
func TestBodyStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
// Create a test body to move around the database and make sure it's really new
body := types.NewTestBody().With().Uncles([]*block.Header{blockfactory.NewTestHeader().With().Extra([]byte("test header")).Header()}).Body()
@ -104,7 +105,7 @@ func TestBodyStorage(t *testing.T) {
// Tests block storage and retrieval operations.
func TestBlockStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
// Create a test block to move around the database and make sure it's really new
block := types.NewBlockWithHeader(blockfactory.NewTestHeader().With().
@ -166,7 +167,7 @@ func TestBlockStorage(t *testing.T) {
// Tests that partial block contents don't get reassembled into full blocks.
func TestPartialBlockStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
block := types.NewBlockWithHeader(blockfactory.NewTestHeader().With().
Extra([]byte("test block")).
TxHash(types.EmptyRootHash).
@ -199,7 +200,7 @@ func TestPartialBlockStorage(t *testing.T) {
// Tests block total difficulty storage and retrieval operations.
func TestTdStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
// Create a test TD to move around the database and make sure it's really new
hash, td := common.Hash{}, big.NewInt(314)
@ -222,7 +223,7 @@ func TestTdStorage(t *testing.T) {
// Tests that canonical numbers can be mapped to hashes and retrieved.
func TestCanonicalMappingStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
// Create a test canonical number and assinged hash to move around
hash, number := common.Hash{0: 0xff}, uint64(314)
@ -245,7 +246,7 @@ func TestCanonicalMappingStorage(t *testing.T) {
// Tests that head headers and head blocks can be assigned, individually.
func TestHeadStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
blockHead := types.NewBlockWithHeader(blockfactory.NewTestHeader().With().Extra([]byte("test block header")).Header())
blockFull := types.NewBlockWithHeader(blockfactory.NewTestHeader().With().Extra([]byte("test block full")).Header())
@ -280,7 +281,7 @@ func TestHeadStorage(t *testing.T) {
// Tests that receipts associated with a single block can be stored and retrieved.
func TestBlockReceiptStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed,

@ -20,11 +20,12 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
blockfactory "github.com/harmony-one/harmony/block/factory"
@ -41,7 +42,7 @@ var (
// Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), 0, big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), 0, big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
@ -116,7 +117,7 @@ func TestLookupStorage(t *testing.T) {
// Test that staking tx hash does not find a plain tx hash (and visa versa) within the same block
func TestMixedLookupStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
tx := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), 0, big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
stx := sampleCreateValidatorStakingTxn()

@ -7,10 +7,11 @@ import (
"strings"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/harmony-one/harmony/block"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state"
@ -1559,7 +1560,7 @@ func makeVWrapperByIndex(index int) staking.ValidatorWrapper {
}
func newTestStateDB() (*state.DB, error) {
return state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
return state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
}
// makeVWrappersForStake makes the default staking.ValidatorWrappers for

@ -18,7 +18,6 @@ package state
import (
"fmt"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
@ -59,28 +58,61 @@ type Database interface {
TrieDB() *trie.Database
}
// Trie is a Ethereum Merkle Trie.
// Trie is a Ethereum Merkle Patricia trie.
type Trie interface {
// GetKey returns the sha3 preimage of a hashed key that was previously used
// to store a value.
//
// TODO(fjl): remove this when SecureTrie is removed
GetKey([]byte) []byte
// TryGet returns the value for key stored in the trie. The value bytes must
// not be modified by the caller. If a node was not found in the database, a
// trie.MissingNodeError is returned.
TryGet(key []byte) ([]byte, error)
// TryUpdate associates key with value in the trie. If value has length zero, any
// existing value is deleted from the trie. The value bytes must not be modified
// by the caller while they are stored in the trie. If a node was not found in the
// database, a trie.MissingNodeError is returned.
TryUpdate(key, value []byte) error
// TryDelete removes any existing value for key from the trie. If a node was not
// found in the database, a trie.MissingNodeError is returned.
TryDelete(key []byte) error
Commit(onleaf trie.LeafCallback) (common.Hash, error)
// Hash returns the root hash of the trie. It does not write to the database and
// can be used even if the trie doesn't have one.
Hash() common.Hash
// Commit writes all nodes to the trie's memory database, tracking the internal
// and external (for account tries) references.
Commit(onleaf trie.LeafCallback) (common.Hash, error)
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key.
NodeIterator(startKey []byte) trie.NodeIterator
GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed
Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error
// Prove constructs a Merkle proof for key. The result contains all encoded nodes
// on the path to the value at key. The value itself is also included in the last
// node and can be retrieved by verifying the proof.
//
// If the trie does not contain a value for key, the returned proof contains all
// nodes of the longest existing prefix of the key (at least the root), ending
// with the node that proves the absence of the key.
Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error
}
// NewDatabase creates a backing store for state. The returned database is safe for
// concurrent use and retains a few recent expanded trie nodes in memory. To keep
// more historical state in memory, use the NewDatabaseWithCache constructor.
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
// historical state in memory, use the NewDatabaseWithCache constructor.
func NewDatabase(db ethdb.Database) Database {
return NewDatabaseWithCache(db, 0)
}
// NewDatabaseWithCache creates a backing store for state. The returned database is safe for
// concurrent use and retains both a few recent expanded trie nodes in memory, as
// well as a lot of collapsed RLP trie nodes in a large memory cache.
// NewDatabaseWithCache creates a backing store for state. The returned database
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
// large memory cache.
func NewDatabaseWithCache(db ethdb.Database, cache int) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{
@ -91,50 +123,22 @@ func NewDatabaseWithCache(db ethdb.Database, cache int) Database {
type cachingDB struct {
db *trie.Database
mu sync.Mutex
pastTries []*trie.SecureTrie
codeSizeCache *lru.Cache
}
// OpenTrie opens the main account trie.
// OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
db.mu.Lock()
defer db.mu.Unlock()
for i := len(db.pastTries) - 1; i >= 0; i-- {
if db.pastTries[i].Hash() == root {
return cachedTrie{db.pastTries[i].Copy(), db}, nil
}
}
tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen)
if err != nil {
return nil, err
}
return cachedTrie{tr, db}, nil
}
func (db *cachingDB) pushTrie(t *trie.SecureTrie) {
db.mu.Lock()
defer db.mu.Unlock()
if len(db.pastTries) >= maxPastTries {
copy(db.pastTries, db.pastTries[1:])
db.pastTries[len(db.pastTries)-1] = t
} else {
db.pastTries = append(db.pastTries, t)
}
return trie.NewSecure(root, db.db)
}
// OpenStorageTrie opens the storage trie of an account.
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
return trie.NewSecure(root, db.db, 0)
return trie.NewSecure(root, db.db)
}
// CopyTrie returns an independent copy of the given trie.
func (db *cachingDB) CopyTrie(t Trie) Trie {
switch t := t.(type) {
case cachedTrie:
return cachedTrie{t.SecureTrie.Copy(), db}
case *trie.SecureTrie:
return t.Copy()
default:
@ -164,21 +168,3 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro
func (db *cachingDB) TrieDB() *trie.Database {
return db.db
}
// cachedTrie inserts its trie into a cachingDB on commit.
type cachedTrie struct {
*trie.SecureTrie
db *cachingDB
}
func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
root, err := m.SecureTrie.Commit(onleaf)
if err == nil {
m.db.pushTrie(m.SecureTrie)
}
return root, err
}
func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
return m.SecureTrie.Prove(key, fromLevel, proofDb)
}

@ -20,78 +20,143 @@ import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/harmony/internal/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
common2 "github.com/harmony-one/harmony/internal/common"
staking "github.com/harmony-one/harmony/staking/types"
)
// DumpAccount ...
// DumpAccount represents an account in the state
type DumpAccount struct {
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root string `json:"root"`
CodeHash string `json:"codeHash"`
Code string `json:"code"`
Storage map[string]string `json:"storage"`
Balance string `json:"balance"`
Nonce uint64 `json:"nonce"`
Root string `json:"root"`
CodeHash string `json:"codeHash"`
Code string `json:"code,omitempty"`
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
}
// Dump ...
// Dump represents the full dump in a collected format, as one large map
type Dump struct {
Root string `json:"root"`
Accounts map[string]DumpAccount `json:"accounts"`
Root string `json:"root"`
Accounts map[common.Address]DumpAccount `json:"accounts"`
}
// iterativeDump is a 'collector'-implementation which dump output line-by-line iteratively
type iterativeDump struct {
*json.Encoder
}
// RawDump ...
func (db *DB) RawDump() Dump {
dump := Dump{
Root: fmt.Sprintf("%x", db.trie.Hash()),
Accounts: make(map[string]DumpAccount),
// Collector interface which the state trie calls during iteration
type collector interface {
onRoot(common.Hash)
onAccount(common.Address, DumpAccount)
}
func (d *Dump) onRoot(root common.Hash) {
d.Root = fmt.Sprintf("%x", root)
}
func (d *Dump) onAccount(addr common.Address, account DumpAccount) {
d.Accounts[addr] = account
}
func (d iterativeDump) onAccount(addr common.Address, account DumpAccount) {
dumpAccount := &DumpAccount{
Balance: account.Balance,
Nonce: account.Nonce,
Root: account.Root,
CodeHash: account.CodeHash,
Code: account.Code,
Storage: account.Storage,
SecureKey: account.SecureKey,
Address: nil,
}
if addr != (common.Address{}) {
dumpAccount.Address = &addr
}
d.Encode(dumpAccount)
}
func (d iterativeDump) onRoot(root common.Hash) {
d.Encode(struct {
Root common.Hash `json:"root"`
}{root})
}
it := trie.NewIterator(db.trie.NodeIterator(nil))
func (s *DB) dump(c collector, excludeCode, excludeStorage, excludeMissingPreimages bool) {
emptyAddress := (common.Address{})
missingPreimages := 0
c.onRoot(s.trie.Hash())
it := trie.NewIterator(s.trie.NodeIterator(nil))
for it.Next() {
addr := db.trie.GetKey(it.Key)
var data Account
if err := rlp.DecodeBytes(it.Value, &data); err != nil {
panic(err)
}
obj := newObject(nil, common.BytesToAddress(addr), data)
var wrapper staking.ValidatorWrapper
wrap := ""
if err := rlp.DecodeBytes(obj.Code(db.db), &wrapper); err != nil {
//
} else {
marsh, err := json.Marshal(wrapper)
if err == nil {
wrap = string(marsh)
}
}
addr := common.BytesToAddress(s.trie.GetKey(it.Key))
obj := newObject(nil, addr, data)
account := DumpAccount{
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: common.Bytes2Hex(data.Root[:]),
CodeHash: common.Bytes2Hex(data.CodeHash),
Code: wrap,
Storage: make(map[string]string),
}
storageIt := trie.NewIterator(obj.getTrie(db.db).NodeIterator(nil))
for storageIt.Next() {
account.Storage[common.Bytes2Hex(db.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
if emptyAddress == addr {
// Preimage missing
missingPreimages++
if excludeMissingPreimages {
continue
}
account.SecureKey = it.Key
}
if !excludeCode {
account.Code = common.Bytes2Hex(obj.Code(s.db))
}
dump.Accounts[common2.MustAddressToBech32(common.BytesToAddress(addr))] = account
if !excludeStorage {
account.Storage = make(map[common.Hash]string)
storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil))
for storageIt.Next() {
_, content, _, err := rlp.Split(storageIt.Value)
if err != nil {
utils.Logger().Err(err).Msg("Failed to decode the value returned by iterator")
continue
}
account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content)
}
}
c.onAccount(addr, account)
}
if missingPreimages > 0 {
utils.Logger().Warn().Int("missing", missingPreimages).Msg("Dump incomplete due to missing preimages")
}
}
// RawDump returns the entire state an a single large object
func (s *DB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump {
dump := &Dump{
Accounts: make(map[common.Address]DumpAccount),
}
return dump
s.dump(dump, excludeCode, excludeStorage, excludeMissingPreimages)
return *dump
}
// Dump ...
func (db *DB) Dump() string {
json, err := json.MarshalIndent(db.RawDump(), "", " ")
// Dump returns a JSON string representing the entire state as a single json-object
func (s *DB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte {
dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages)
json, err := json.MarshalIndent(dump, "", " ")
if err != nil {
fmt.Println("dump err", err)
}
return json
}
return string(json)
// IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout
func (s *DB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) {
s.dump(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages)
}

@ -19,14 +19,15 @@ package state
import (
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
)
var addr = common.BytesToAddress([]byte("test"))
func create() (*ManagedState, *account) {
statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
ms := ManageState(statedb)
ms.DB.SetNonce(addr, 100)
ms.accounts[addr] = newAccount(ms.DB.getStateObject(addr))

@ -21,6 +21,9 @@ import (
"fmt"
"io"
"math/big"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -34,15 +37,15 @@ var emptyCodeHash = crypto.Keccak256(nil)
// Code ...
type Code []byte
func (code Code) String() string {
return string(code) //strings.Join(Disassemble(so), " ")
func (c Code) String() string {
return string(c) //strings.Join(Disassemble(c), " ")
}
// Storage ...
type Storage map[common.Hash]common.Hash
func (storage Storage) String() (str string) {
for key, value := range storage {
func (s Storage) String() (str string) {
for key, value := range s {
str += fmt.Sprintf("%X : %X\n", key, value)
}
@ -50,9 +53,9 @@ func (storage Storage) String() (str string) {
}
// Copy ...
func (storage Storage) Copy() Storage {
func (s Storage) Copy() Storage {
cpy := make(Storage)
for key, value := range storage {
for key, value := range s {
cpy[key] = value
}
@ -75,15 +78,17 @@ type Object struct {
// State objects are used by the consensus core and VM which are
// unable to deal with database-level errors. Any error that occurs
// during a database read is memoized here and will eventually be returned
// by DB.Commit.
// by StateDB.Commit.
dbErr error
// Write caches.
trie Trie // storage trie, which becomes non-nil on first access
code Code // contract bytecode, which gets set when code is loaded
originStorage Storage // Storage cache of original entries to dedup rewrites
dirtyStorage Storage // Storage entries that need to be flushed to disk
originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
// Cache flags.
// When an object is marked suicided it will be delete from the trie
@ -94,8 +99,8 @@ type Object struct {
}
// empty returns whether the account is considered empty.
func (so *Object) empty() bool {
return so.data.Nonce == 0 && so.data.Balance.Sign() == 0 && bytes.Equal(so.data.CodeHash, emptyCodeHash)
func (s *Object) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
}
// Account is the Ethereum consensus representation of accounts.
@ -115,205 +120,276 @@ func newObject(db *DB, address common.Address, data Account) *Object {
if data.CodeHash == nil {
data.CodeHash = emptyCodeHash
}
if data.Root == (common.Hash{}) {
data.Root = emptyRoot
}
return &Object{
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
data: data,
originStorage: make(Storage),
dirtyStorage: make(Storage),
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
data: data,
originStorage: make(Storage),
pendingStorage: make(Storage),
dirtyStorage: make(Storage),
}
}
// EncodeRLP implements rlp.Encoder.
func (so *Object) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, so.data)
func (s *Object) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, s.data)
}
// setError remembers the first non-nil error it is called with.
func (so *Object) setError(err error) {
if so.dbErr == nil {
so.dbErr = err
func (s *Object) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
}
}
func (so *Object) markSuicided() {
so.suicided = true
func (s *Object) markSuicided() {
s.suicided = true
}
func (so *Object) touch() {
so.db.journal.append(touchChange{
account: &so.address,
func (s *Object) touch() {
s.db.journal.append(touchChange{
account: &s.address,
})
if so.address == ripemd {
if s.address == ripemd {
// Explicitly put it in the dirty-cache, which is otherwise generated from
// flattened journals.
so.db.journal.dirty(so.address)
s.db.journal.dirty(s.address)
}
}
func (so *Object) getTrie(db Database) Trie {
if so.trie == nil {
func (s *Object) getTrie(db Database) Trie {
if s.trie == nil {
var err error
so.trie, err = db.OpenStorageTrie(so.addrHash, so.data.Root)
s.trie, err = db.OpenStorageTrie(s.addrHash, s.data.Root)
if err != nil {
so.trie, _ = db.OpenStorageTrie(so.addrHash, common.Hash{})
so.setError(fmt.Errorf("can't create storage trie: %v", err))
s.trie, _ = db.OpenStorageTrie(s.addrHash, common.Hash{})
s.setError(fmt.Errorf("can't create storage trie: %v", err))
}
}
return so.trie
return s.trie
}
// GetState retrieves a value from the account storage trie.
func (so *Object) GetState(db Database, key common.Hash) common.Hash {
func (s *Object) GetState(db Database, key common.Hash) common.Hash {
// If the fake storage is set, only lookup the state here(in the debugging mode)
if s.fakeStorage != nil {
return s.fakeStorage[key]
}
// If we have a dirty value for this state entry, return it
value, dirty := so.dirtyStorage[key]
value, dirty := s.dirtyStorage[key]
if dirty {
return value
}
// Otherwise return the entry's original value
return so.GetCommittedState(db, key)
return s.GetCommittedState(db, key)
}
// GetCommittedState retrieves a value from the committed account storage trie.
func (so *Object) GetCommittedState(db Database, key common.Hash) common.Hash {
// If we have the original value cached, return that
value, cached := so.originStorage[key]
if cached {
func (s *Object) GetCommittedState(db Database, key common.Hash) common.Hash {
// If the fake storage is set, only lookup the state here(in the debugging mode)
if s.fakeStorage != nil {
return s.fakeStorage[key]
}
// If we have a pending write or clean cached, return that
if value, pending := s.pendingStorage[key]; pending {
return value
}
if value, cached := s.originStorage[key]; cached {
return value
}
// Track the amount of time wasted on reading the storage trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now())
}
// Otherwise load the value from the database
enc, err := so.getTrie(db).TryGet(key[:])
enc, err := s.getTrie(db).TryGet(key[:])
if err != nil {
so.setError(err)
s.setError(err)
return common.Hash{}
}
var value common.Hash
if len(enc) > 0 {
_, content, _, err := rlp.Split(enc)
if err != nil {
so.setError(err)
s.setError(err)
}
value.SetBytes(content)
}
so.originStorage[key] = value
s.originStorage[key] = value
return value
}
// SetState updates a value in account storage.
// to remove, set value to common.Hash{}
func (so *Object) SetState(db Database, key, value common.Hash) {
func (s *Object) SetState(db Database, key, value common.Hash) {
// If the fake storage is set, put the temporary state update here.
if s.fakeStorage != nil {
s.fakeStorage[key] = value
return
}
// If the new value is the same as old, don't set
prev := so.GetState(db, key)
prev := s.GetState(db, key)
if prev == value {
return
}
// New value is different, update and journal the change
so.db.journal.append(storageChange{
account: &so.address,
s.db.journal.append(storageChange{
account: &s.address,
key: key,
prevalue: prev,
})
so.setState(key, value)
s.setState(key, value)
}
func (so *Object) setState(key, value common.Hash) {
so.dirtyStorage[key] = value
// SetStorage replaces the entire state storage with the given one.
//
// After this function is called, all original state will be ignored and state
// lookup only happens in the fake state storage.
//
// Note this function should only be used for debugging purpose.
func (s *Object) SetStorage(storage map[common.Hash]common.Hash) {
// Allocate fake storage if it's nil.
if s.fakeStorage == nil {
s.fakeStorage = make(Storage)
}
for key, value := range storage {
s.fakeStorage[key] = value
}
// Don't bother journal since this function should only be used for
// debugging and the `fake` storage won't be committed to database.
}
func (s *Object) setState(key, value common.Hash) {
s.dirtyStorage[key] = value
}
// finalise moves all dirty storage slots into the pending area to be hashed or
// committed later. It is invoked at the end of every transaction.
func (s *Object) finalise() {
for key, value := range s.dirtyStorage {
s.pendingStorage[key] = value
}
if len(s.dirtyStorage) > 0 {
s.dirtyStorage = make(Storage)
}
}
// updateTrie writes cached storage modifications into the object's storage trie.
func (so *Object) updateTrie(db Database) Trie {
tr := so.getTrie(db)
for key, value := range so.dirtyStorage {
delete(so.dirtyStorage, key)
func (s *Object) updateTrie(db Database) Trie {
// Make sure all dirty slots are finalized into the pending storage area
s.finalise()
// Track the amount of time wasted on updating the storge trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now())
}
// Insert all the pending updates into the trie
tr := s.getTrie(db)
for key, value := range s.pendingStorage {
// Skip noop changes, persist actual changes
if value == so.originStorage[key] {
if value == s.originStorage[key] {
continue
}
so.originStorage[key] = value
s.originStorage[key] = value
if (value == common.Hash{}) {
so.setError(tr.TryDelete(key[:]))
s.setError(tr.TryDelete(key[:]))
continue
}
// Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
so.setError(tr.TryUpdate(key[:], v))
v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
s.setError(tr.TryUpdate(key[:], v))
}
if len(s.pendingStorage) > 0 {
s.pendingStorage = make(Storage)
}
return tr
}
// UpdateRoot sets the trie root to the current root hash of
func (so *Object) updateRoot(db Database) {
so.updateTrie(db)
so.data.Root = so.trie.Hash()
func (s *Object) updateRoot(db Database) {
s.updateTrie(db)
// Track the amount of time wasted on hashing the storge trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now())
}
s.data.Root = s.trie.Hash()
}
// CommitTrie the storage trie of the object to db.
// This updates the trie root.
func (so *Object) CommitTrie(db Database) error {
so.updateTrie(db)
if so.dbErr != nil {
return so.dbErr
func (s *Object) CommitTrie(db Database) error {
s.updateTrie(db)
if s.dbErr != nil {
return s.dbErr
}
// Track the amount of time wasted on committing the storge trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
}
root, err := so.trie.Commit(nil)
root, err := s.trie.Commit(nil)
if err == nil {
so.data.Root = root
s.data.Root = root
}
return err
}
// AddBalance removes amount from c's balance.
// It is used to add funds to the destination account of a transfer.
func (so *Object) AddBalance(amount *big.Int) {
func (s *Object) AddBalance(amount *big.Int) {
// EIP158: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
if amount.Sign() == 0 {
if so.empty() {
so.touch()
if s.empty() {
s.touch()
}
return
}
so.SetBalance(new(big.Int).Add(so.Balance(), amount))
s.SetBalance(new(big.Int).Add(s.Balance(), amount))
}
// SubBalance removes amount from c's balance.
// It is used to remove funds from the origin account of a transfer.
func (so *Object) SubBalance(amount *big.Int) {
func (s *Object) SubBalance(amount *big.Int) {
if amount.Sign() == 0 {
return
}
so.SetBalance(new(big.Int).Sub(so.Balance(), amount))
s.SetBalance(new(big.Int).Sub(s.Balance(), amount))
}
// SetBalance ...
func (so *Object) SetBalance(amount *big.Int) {
so.db.journal.append(balanceChange{
account: &so.address,
prev: new(big.Int).Set(so.data.Balance),
func (s *Object) SetBalance(amount *big.Int) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(big.Int).Set(s.data.Balance),
})
so.setBalance(amount)
s.setBalance(amount)
}
func (so *Object) setBalance(amount *big.Int) {
so.data.Balance = amount
func (s *Object) setBalance(amount *big.Int) {
s.data.Balance = amount
}
// ReturnGas returns the gas back to the origin. Used by the Virtual machine or Closures
func (so *Object) ReturnGas(gas *big.Int) {}
// ReturnGas the gas back to the origin. Used by the Virtual machine or Closures
func (s *Object) ReturnGas(gas *big.Int) {}
func (so *Object) deepCopy(db *DB) *Object {
stateObject := newObject(db, so.address, so.data)
if so.trie != nil {
stateObject.trie = db.db.CopyTrie(so.trie)
func (s *Object) deepCopy(db *DB) *Object {
stateObject := newObject(db, s.address, s.data)
if s.trie != nil {
stateObject.trie = db.db.CopyTrie(s.trie)
}
stateObject.code = so.code
stateObject.dirtyStorage = so.dirtyStorage.Copy()
stateObject.originStorage = so.originStorage.Copy()
stateObject.suicided = so.suicided
stateObject.dirtyCode = so.dirtyCode
stateObject.deleted = so.deleted
stateObject.code = s.code
stateObject.dirtyStorage = s.dirtyStorage.Copy()
stateObject.originStorage = s.originStorage.Copy()
stateObject.pendingStorage = s.pendingStorage.Copy()
stateObject.suicided = s.suicided
stateObject.dirtyCode = s.dirtyCode
stateObject.deleted = s.deleted
return stateObject
}
@ -322,80 +398,80 @@ func (so *Object) deepCopy(db *DB) *Object {
//
// Address returns the address of the contract/account
func (so *Object) Address() common.Address {
return so.address
func (s *Object) Address() common.Address {
return s.address
}
// Code returns the contract code associated with this object, if any.
func (so *Object) Code(db Database) []byte {
if so.code != nil {
return so.code
func (s *Object) Code(db Database) []byte {
if s.code != nil {
return s.code
}
if bytes.Equal(so.CodeHash(), emptyCodeHash) {
if bytes.Equal(s.CodeHash(), emptyCodeHash) {
return nil
}
code, err := db.ContractCode(so.addrHash, common.BytesToHash(so.CodeHash()))
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash()))
if err != nil {
so.setError(fmt.Errorf("can't load code hash %x: %v", so.CodeHash(), err))
s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
}
so.code = code
s.code = code
return code
}
// SetCode ...
func (so *Object) SetCode(codeHash common.Hash, code []byte) {
prevcode := so.Code(so.db.db)
so.db.journal.append(codeChange{
account: &so.address,
prevhash: so.CodeHash(),
func (s *Object) SetCode(codeHash common.Hash, code []byte) {
prevcode := s.Code(s.db.db)
s.db.journal.append(codeChange{
account: &s.address,
prevhash: s.CodeHash(),
prevcode: prevcode,
})
so.setCode(codeHash, code)
s.setCode(codeHash, code)
}
func (so *Object) setCode(codeHash common.Hash, code []byte) {
so.code = code
so.data.CodeHash = codeHash[:]
so.dirtyCode = true
func (s *Object) setCode(codeHash common.Hash, code []byte) {
s.code = code
s.data.CodeHash = codeHash[:]
s.dirtyCode = true
}
// SetNonce ...
func (so *Object) SetNonce(nonce uint64) {
so.db.journal.append(nonceChange{
account: &so.address,
prev: so.data.Nonce,
func (s *Object) SetNonce(nonce uint64) {
s.db.journal.append(nonceChange{
account: &s.address,
prev: s.data.Nonce,
})
so.setNonce(nonce)
s.setNonce(nonce)
}
func (so *Object) setNonce(nonce uint64) {
so.data.Nonce = nonce
func (s *Object) setNonce(nonce uint64) {
s.data.Nonce = nonce
}
// CodeHash ...
func (so *Object) CodeHash() []byte {
return so.data.CodeHash
func (s *Object) CodeHash() []byte {
return s.data.CodeHash
}
// Balance ...
func (so *Object) Balance() *big.Int {
return so.data.Balance
func (s *Object) Balance() *big.Int {
return s.data.Balance
}
// Nonce ...
func (so *Object) Nonce() uint64 {
return so.data.Nonce
func (s *Object) Nonce() uint64 {
return s.data.Nonce
}
// Value never called, but must be present to allow Object to be used
// Value Never called, but must be present to allow stateObject to be used
// as a vm.Account interface that also satisfies the vm.ContractRef
// interface. Interfaces are awesome.
func (so *Object) Value() *big.Int {
panic("Value on Object should never be called")
func (s *Object) Value() *big.Int {
panic("Value on stateObject should never be called")
}
// IsValidator checks whether it is a validator object
func (so *Object) IsValidator(db Database) bool {
value := so.GetState(db, staking.IsValidatorKey)
func (s *Object) IsValidator(db Database) bool {
value := s.GetState(db, staking.IsValidatorKey)
return value != (common.Hash{})
}

@ -21,22 +21,29 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
checker "gopkg.in/check.v1"
)
type StateSuite struct {
db *ethdb.MemDatabase
var toAddr = common.BytesToAddress
type stateTest struct {
db ethdb.Database
state *DB
}
var _ = checker.Suite(&StateSuite{})
func newStateTest() *stateTest {
db := rawdb.NewMemoryDatabase()
sdb, _ := New(common.Hash{}, NewDatabase(db))
return &stateTest{db: db, state: sdb}
}
var toAddr = common.BytesToAddress
func TestDump(t *testing.T) {
s := newStateTest()
func (s *StateSuite) TestDump(c *checker.C) {
// generate a few entries
obj1 := s.state.GetOrNewStateObject(toAddr([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
@ -51,47 +58,38 @@ func (s *StateSuite) TestDump(c *checker.C) {
s.state.Commit(false)
// check that dump contains the state objects that are in trie
got := string(s.state.Dump())
got := string(s.state.Dump(false, false, true))
want := `{
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
"accounts": {
"0000000000000000000000000000000000000001": {
"0x0000000000000000000000000000000000000001": {
"balance": "22",
"nonce": 0,
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"code": "",
"storage": {}
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
},
"0000000000000000000000000000000000000002": {
"0x0000000000000000000000000000000000000002": {
"balance": "44",
"nonce": 0,
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"code": "",
"storage": {}
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
},
"0000000000000000000000000000000000000102": {
"0x0000000000000000000000000000000000000102": {
"balance": "0",
"nonce": 0,
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
"code": "03030303030303",
"storage": {}
"code": "03030303030303"
}
}
}`
if got != want {
c.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want)
t.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want)
}
}
func (s *StateSuite) SetUpTest(c *checker.C) {
s.db = ethdb.NewMemDatabase()
s.state, _ = New(common.Hash{}, NewDatabase(s.db))
}
func (s *StateSuite) TestNull(c *checker.C) {
func TestNull(t *testing.T) {
s := newStateTest()
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
s.state.CreateAccount(address)
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
@ -101,18 +99,19 @@ func (s *StateSuite) TestNull(c *checker.C) {
s.state.Commit(false)
if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) {
c.Errorf("expected empty current value, got %x", value)
t.Errorf("expected empty current value, got %x", value)
}
if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) {
c.Errorf("expected empty committed value, got %x", value)
t.Errorf("expected empty committed value, got %x", value)
}
}
func (s *StateSuite) TestSnapshot(c *checker.C) {
func TestSnapshot(t *testing.T) {
stateobjaddr := toAddr([]byte("aa"))
var storageaddr common.Hash
data1 := common.BytesToHash([]byte{42})
data2 := common.BytesToHash([]byte{43})
s := newStateTest()
// snapshot the genesis state
genesis := s.state.Snapshot()
@ -125,23 +124,30 @@ func (s *StateSuite) TestSnapshot(c *checker.C) {
s.state.SetState(stateobjaddr, storageaddr, data2)
s.state.RevertToSnapshot(snapshot)
c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, data1)
c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
if v := s.state.GetState(stateobjaddr, storageaddr); v != data1 {
t.Errorf("wrong storage value %v, want %v", v, data1)
}
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
}
// revert up to the genesis state and ensure correct content
s.state.RevertToSnapshot(genesis)
c.Assert(s.state.GetState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
c.Assert(s.state.GetCommittedState(stateobjaddr, storageaddr), checker.DeepEquals, common.Hash{})
if v := s.state.GetState(stateobjaddr, storageaddr); v != (common.Hash{}) {
t.Errorf("wrong storage value %v, want %v", v, common.Hash{})
}
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
}
}
func (s *StateSuite) TestSnapshotEmpty(c *checker.C) {
func TestSnapshotEmpty(t *testing.T) {
s := newStateTest()
s.state.RevertToSnapshot(s.state.Snapshot())
}
// use testing instead of checker because checker does not support
// printing/logging in tests (-check.vv does not work)
func TestSnapshot2(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
stateobjaddr0 := toAddr([]byte("so0"))
stateobjaddr1 := toAddr([]byte("so1"))

@ -21,6 +21,9 @@ import (
"fmt"
"math/big"
"sort"
"time"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -43,8 +46,8 @@ type revision struct {
}
var (
// emptyState is the known hash of an empty state trie entry.
emptyState = crypto.Keccak256Hash(nil)
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyCode is the known hash of the empty EVM bytecode.
emptyCode = crypto.Keccak256Hash(nil)
@ -57,6 +60,10 @@ func (n *proofList) Put(key []byte, value []byte) error {
return nil
}
func (n *proofList) Delete(key []byte) error {
panic("not supported")
}
// DB within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
@ -67,9 +74,10 @@ type DB struct {
trie Trie
// This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects map[common.Address]*Object
stateObjectsDirty map[common.Address]struct{}
stateValidators map[common.Address]*stk.ValidatorWrapper
stateObjects map[common.Address]*Object
stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
stateObjectsDirty map[common.Address]struct{}
stateValidators map[common.Address]*stk.ValidatorWrapper
// DB error.
// State objects are used by the consensus core and VM which are
@ -93,6 +101,16 @@ type DB struct {
journal *journal
validRevisions []revision
nextRevisionID int
// Measurements gathered during execution for debugging purposes
AccountReads time.Duration
AccountHashes time.Duration
AccountUpdates time.Duration
AccountCommits time.Duration
StorageReads time.Duration
StorageHashes time.Duration
StorageUpdates time.Duration
StorageCommits time.Duration
}
// New creates a new state from a given trie.
@ -102,14 +120,15 @@ func New(root common.Hash, db Database) (*DB, error) {
return nil, err
}
return &DB{
db: db,
trie: tr,
stateObjects: make(map[common.Address]*Object),
stateObjectsDirty: make(map[common.Address]struct{}),
stateValidators: make(map[common.Address]*stk.ValidatorWrapper),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
db: db,
trie: tr,
stateObjects: make(map[common.Address]*Object),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
stateValidators: make(map[common.Address]*stk.ValidatorWrapper),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
}, nil
}
@ -133,6 +152,7 @@ func (db *DB) Reset(root common.Hash) error {
}
db.trie = tr
db.stateObjects = make(map[common.Address]*Object)
db.stateObjectsPending = make(map[common.Address]struct{})
db.stateObjectsDirty = make(map[common.Address]struct{})
db.stateValidators = make(map[common.Address]*stk.ValidatorWrapper)
db.thash = common.Hash{}
@ -234,6 +254,16 @@ func (db *DB) GetNonce(addr common.Address) uint64 {
return 0
}
// TxIndex returns the current transaction index set by Prepare.
func (db *DB) TxIndex() int {
return db.txIndex
}
// BlockHash returns the current block hash set by Prepare.
func (db *DB) BlockHash() common.Hash {
return db.bhash
}
// GetCode ...
func (db *DB) GetCode(addr common.Address) []byte {
stateObject := db.getStateObject(addr)
@ -409,9 +439,15 @@ func (db *DB) Suicide(addr common.Address) bool {
//
// updateStateObject writes the given object to the trie.
func (db *DB) updateStateObject(stateObject *Object) {
addr := stateObject.Address()
data, err := rlp.EncodeToBytes(stateObject)
func (db *DB) updateStateObject(obj *Object) {
// Track the amount of time wasted on updating the account from the trie
if metrics.EnabledExpensive {
defer func(start time.Time) { db.AccountUpdates += time.Since(start) }(time.Now())
}
// Encode the account and update the account trie
addr := obj.Address()
data, err := rlp.EncodeToBytes(obj)
if err != nil {
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
}
@ -419,23 +455,40 @@ func (db *DB) updateStateObject(stateObject *Object) {
}
// deleteStateObject removes the given object from the state trie.
func (db *DB) deleteStateObject(stateObject *Object) {
stateObject.deleted = true
addr := stateObject.Address()
func (db *DB) deleteStateObject(obj *Object) {
// Track the amount of time wasted on deleting the account from the trie
if metrics.EnabledExpensive {
defer func(start time.Time) { db.AccountUpdates += time.Since(start) }(time.Now())
}
// Delete the account from the trie
addr := obj.Address()
db.setError(db.trie.TryDelete(addr[:]))
}
// Retrieve a state object given by the address. Returns nil if not found.
func (db *DB) getStateObject(addr common.Address) (stateObject *Object) {
// Prefer 'live' objects.
if obj := db.stateObjects[addr]; obj != nil {
if obj.deleted {
return nil
}
// getStateObject retrieves a state object given by the address, returning nil if
// the object is not found or was deleted in this execution context. If you need
// to differentiate between non-existent/just-deleted, use getDeletedStateObject.
func (db *DB) getStateObject(addr common.Address) *Object {
if obj := db.getDeletedStateObject(addr); obj != nil && !obj.deleted {
return obj
}
return nil
}
// Load the object from the database.
// getDeletedStateObject is similar to getStateObject, but instead of returning
// nil for a deleted state object, it returns the actual object with the deleted
// flag set. This is needed by the state journal to revert to the correct s-
// destructed object instead of wiping all knowledge about the state object.
func (db *DB) getDeletedStateObject(addr common.Address) *Object {
// Prefer live objects if any is available
if obj := db.stateObjects[addr]; obj != nil {
return obj
}
// Track the amount of time wasted on loading the object from the database
if metrics.EnabledExpensive {
defer func(start time.Time) { db.AccountReads += time.Since(start) }(time.Now())
}
// Load the object from the database
enc, err := db.trie.TryGet(addr[:])
if len(enc) == 0 {
db.setError(err)
@ -446,7 +499,7 @@ func (db *DB) getStateObject(addr common.Address) (stateObject *Object) {
log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
// Insert into the live set.
// Insert into the live set
obj := newObject(db, addr, data)
db.setStateObject(obj)
return obj
@ -459,7 +512,7 @@ func (db *DB) setStateObject(object *Object) {
// GetOrNewStateObject retrieves a state object or create a new state object if nil.
func (db *DB) GetOrNewStateObject(addr common.Address) *Object {
stateObject := db.getStateObject(addr)
if stateObject == nil || stateObject.deleted {
if stateObject == nil {
stateObject, _ = db.createObject(addr)
}
return stateObject
@ -468,7 +521,8 @@ func (db *DB) GetOrNewStateObject(addr common.Address) *Object {
// createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value.
func (db *DB) createObject(addr common.Address) (newobj, prev *Object) {
prev = db.getStateObject(addr)
prev = db.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
newobj = newObject(db, addr, Account{})
newobj.setNonce(0) // sets the object to dirty
if prev == nil {
@ -498,20 +552,33 @@ func (db *DB) CreateAccount(addr common.Address) {
}
// ForEachStorage ...
func (db *DB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) {
func (db *DB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error {
so := db.getStateObject(addr)
if so == nil {
return
return nil
}
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
for it.Next() {
key := common.BytesToHash(db.trie.GetKey(it.Key))
if value, dirty := so.dirtyStorage[key]; dirty {
cb(key, value)
if !cb(key, value) {
return nil
}
continue
}
cb(key, common.BytesToHash(it.Value))
if len(it.Value) > 0 {
_, content, _, err := rlp.Split(it.Value)
if err != nil {
return err
}
if !cb(key, common.BytesToHash(content)) {
return nil
}
}
}
return nil
}
// Copy creates a deep, independent copy of the state.
@ -519,16 +586,17 @@ func (db *DB) ForEachStorage(addr common.Address, cb func(key, value common.Hash
func (db *DB) Copy() *DB {
// Copy all the basic fields, initialize the memory ones
state := &DB{
db: db.db,
trie: db.db.CopyTrie(db.trie),
stateObjects: make(map[common.Address]*Object, len(db.journal.dirties)),
stateObjectsDirty: make(map[common.Address]struct{}, len(db.journal.dirties)),
stateValidators: make(map[common.Address]*stk.ValidatorWrapper),
refund: db.refund,
logs: make(map[common.Hash][]*types.Log, len(db.logs)),
logSize: db.logSize,
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
db: db.db,
trie: db.db.CopyTrie(db.trie),
stateObjects: make(map[common.Address]*Object, len(db.journal.dirties)),
stateObjectsPending: make(map[common.Address]struct{}, len(db.stateObjectsPending)),
stateObjectsDirty: make(map[common.Address]struct{}, len(db.journal.dirties)),
stateValidators: make(map[common.Address]*stk.ValidatorWrapper),
refund: db.refund,
logs: make(map[common.Hash][]*types.Log, len(db.logs)),
logSize: db.logSize,
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
}
// Copy the dirty states, logs, and preimages
for addr := range db.journal.dirties {
@ -537,20 +605,30 @@ func (db *DB) Copy() *DB {
// in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for
// nil
if object, exist := db.stateObjects[addr]; exist {
// Even though the original object is dirty, we are not copying the journal,
// so we need to make sure that anyside effect the journal would have caused
// during a commit (or similar op) is already applied to the copy.
state.stateObjects[addr] = object.deepCopy(state)
state.stateObjectsDirty[addr] = struct{}{}
state.stateObjectsDirty[addr] = struct{}{} // Mark the copy dirty to force internal (code/state) commits
state.stateObjectsPending[addr] = struct{}{} // Mark the copy pending to force external (account) commits
}
}
// Above, we don't copy the actual journal. This means that if the copy is copied, the
// loop above will be a no-op, since the copy's journal is empty.
// Thus, here we iterate over stateObjects, to enable copies of copies
for addr := range db.stateObjectsPending {
if _, exist := state.stateObjects[addr]; !exist {
state.stateObjects[addr] = db.stateObjects[addr].deepCopy(state)
}
state.stateObjectsPending[addr] = struct{}{}
}
for addr := range db.stateObjectsDirty {
if _, exist := state.stateObjects[addr]; !exist {
state.stateObjects[addr] = db.stateObjects[addr].deepCopy(state)
state.stateObjectsDirty[addr] = struct{}{}
}
state.stateObjectsDirty[addr] = struct{}{}
}
for hash, logs := range db.logs {
cpy := make([]*types.Log, len(logs))
for i, l := range logs {
@ -598,28 +676,28 @@ func (db *DB) GetRefund() uint64 {
// and clears the journal as well as the refunds.
func (db *DB) Finalise(deleteEmptyObjects bool) {
// Commit validator changes in cache to stateObjects
// TODO: remove validator cache after commit
for addr, val := range db.stateValidators {
db.UpdateValidatorWrapper(addr, val)
}
for addr := range db.journal.dirties {
stateObject, exist := db.stateObjects[addr]
obj, exist := db.stateObjects[addr]
if !exist {
// ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2
// That tx goes out of gas, and although the notion of 'touched' does not exist there, the
// touch-event will still be recorded in the journal. Since ripeMD is a special snowflake,
// it will persist in the journal even though the journal is reverted. In this special circumstance,
// it may exist in `db.journal.dirties` but not in `db.stateObjects`.
// it may exist in `s.journal.dirties` but not in `s.stateObjects`.
// Thus, we can safely ignore it here
continue
}
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
db.deleteStateObject(stateObject)
if obj.suicided || (deleteEmptyObjects && obj.empty()) {
obj.deleted = true
} else {
stateObject.updateRoot(db.db)
db.updateStateObject(stateObject)
obj.finalise()
}
db.stateObjectsPending[addr] = struct{}{}
db.stateObjectsDirty[addr] = struct{}{}
}
// Invalidate journal because reverting across transactions is not allowed.
@ -630,7 +708,25 @@ func (db *DB) Finalise(deleteEmptyObjects bool) {
// It is called in between transactions to get the root hash that
// goes into transaction receipts.
func (db *DB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Finalise all the dirty storage states and write them into the tries
db.Finalise(deleteEmptyObjects)
for addr := range db.stateObjectsPending {
obj := db.stateObjects[addr]
if obj.deleted {
db.deleteStateObject(obj)
} else {
obj.updateRoot(db.db)
db.updateStateObject(obj)
}
}
if len(db.stateObjectsPending) > 0 {
db.stateObjectsPending = make(map[common.Address]struct{})
}
// Track the amount of time wasted on hashing the account trie
if metrics.EnabledExpensive {
defer func(start time.Time) { db.AccountHashes += time.Since(start) }(time.Now())
}
return db.trie.Hash()
}
@ -650,41 +746,36 @@ func (db *DB) clearJournalAndRefund() {
// Commit writes the state to the underlying in-memory trie database.
func (db *DB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
defer db.clearJournalAndRefund()
// Finalize any pending changes and merge everything into the tries
db.IntermediateRoot(deleteEmptyObjects)
for addr := range db.journal.dirties {
db.stateObjectsDirty[addr] = struct{}{}
}
// Commit objects to the trie.
for addr, stateObject := range db.stateObjects {
_, isDirty := db.stateObjectsDirty[addr]
switch {
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
// If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie.
db.deleteStateObject(stateObject)
case isDirty:
// Commit objects to the trie, measuring the elapsed time
for addr := range db.stateObjectsDirty {
if obj := db.stateObjects[addr]; !obj.deleted {
// Write any contract code associated with the state object
if stateObject.code != nil && stateObject.dirtyCode {
db.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code)
stateObject.dirtyCode = false
if obj.code != nil && obj.dirtyCode {
db.db.TrieDB().InsertBlob(common.BytesToHash(obj.CodeHash()), obj.code)
obj.dirtyCode = false
}
// Write any storage changes in the state object to its storage trie.
if err := stateObject.CommitTrie(db.db); err != nil {
// Write any storage changes in the state object to its storage trie
if err := obj.CommitTrie(db.db); err != nil {
return common.Hash{}, err
}
// Update the object in the main account trie.
db.updateStateObject(stateObject)
}
delete(db.stateObjectsDirty, addr)
}
// Write trie changes.
root, err = db.trie.Commit(func(leaf []byte, parent common.Hash) error {
if len(db.stateObjectsDirty) > 0 {
db.stateObjectsDirty = make(map[common.Address]struct{})
}
// Write the account trie changes, measuing the amount of wasted time
if metrics.EnabledExpensive {
defer func(start time.Time) { db.AccountCommits += time.Since(start) }(time.Now())
}
return db.trie.Commit(func(leaf []byte, parent common.Hash) error {
var account Account
if err := rlp.DecodeBytes(leaf, &account); err != nil {
return nil
}
if account.Root != emptyState {
if account.Root != emptyRoot {
db.db.TrieDB().Reference(account.Root, parent)
}
code := common.BytesToHash(account.CodeHash)
@ -693,8 +784,6 @@ func (db *DB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
}
return nil
})
//log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())
return root, err
}
var (

@ -25,22 +25,21 @@ import (
"math/rand"
"reflect"
"strings"
"sync"
"testing"
"testing/quick"
check "gopkg.in/check.v1"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
)
// Tests that updating a state trie does not leak any database writes prior to
// actually committing the state.
func TestUpdateLeaks(t *testing.T) {
// Create an empty state database
db := ethdb.NewMemDatabase()
db := rawdb.NewMemoryDatabase()
state, _ := New(common.Hash{}, NewDatabase(db))
// Update it with some accounts
@ -54,21 +53,27 @@ func TestUpdateLeaks(t *testing.T) {
if i%3 == 0 {
state.SetCode(addr, []byte{i, i, i, i, i})
}
state.IntermediateRoot(false)
}
root := state.IntermediateRoot(false)
if err := state.Database().TrieDB().Commit(root, false); err != nil {
t.Errorf("can not commit trie %v to persistent database", root.Hex())
}
// Ensure that no data was leaked into the database
for _, key := range db.Keys() {
value, _ := db.Get(key)
t.Errorf("State leaked into database: %x -> %x", key, value)
it := db.NewIterator()
for it.Next() {
t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
}
it.Release()
}
// Tests that no intermediate state of an object is stored into the database,
// only the one right before the commit.
func TestIntermediateLeaks(t *testing.T) {
// Create two state databases, one transitioning to the final state, the other final from the beginning
transDb := ethdb.NewMemDatabase()
finalDb := ethdb.NewMemDatabase()
transDb := rawdb.NewMemoryDatabase()
finalDb := rawdb.NewMemoryDatabase()
transState, _ := New(common.Hash{}, NewDatabase(transDb))
finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
@ -86,34 +91,56 @@ func TestIntermediateLeaks(t *testing.T) {
// Modify the transient state.
for i := byte(0); i < 255; i++ {
modify(transState, common.Address{byte(i)}, i, 0)
modify(transState, common.Address{i}, i, 0)
}
// Write modifications to trie.
transState.IntermediateRoot(false)
// Overwrite all the data with new values in the transient database.
for i := byte(0); i < 255; i++ {
modify(transState, common.Address{byte(i)}, i, 99)
modify(finalState, common.Address{byte(i)}, i, 99)
modify(transState, common.Address{i}, i, 99)
modify(finalState, common.Address{i}, i, 99)
}
// Commit and cross check the databases.
if _, err := transState.Commit(false); err != nil {
transRoot, err := transState.Commit(false)
if err != nil {
t.Fatalf("failed to commit transition state: %v", err)
}
if _, err := finalState.Commit(false); err != nil {
if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil {
t.Errorf("can not commit trie %v to persistent database", transRoot.Hex())
}
finalRoot, err := finalState.Commit(false)
if err != nil {
t.Fatalf("failed to commit final state: %v", err)
}
for _, key := range finalDb.Keys() {
if _, err := transDb.Get(key); err != nil {
val, _ := finalDb.Get(key)
t.Errorf("entry missing from the transition database: %x -> %x", key, val)
if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil {
t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex())
}
it := finalDb.NewIterator()
for it.Next() {
key, fvalue := it.Key(), it.Value()
tvalue, err := transDb.Get(key)
if err != nil {
t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue)
}
if !bytes.Equal(fvalue, tvalue) {
t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
}
}
for _, key := range transDb.Keys() {
if _, err := finalDb.Get(key); err != nil {
val, _ := transDb.Get(key)
t.Errorf("extra entry in the transition database: %x -> %x", key, val)
it.Release()
it = transDb.NewIterator()
for it.Next() {
key, tvalue := it.Key(), it.Value()
fvalue, err := finalDb.Get(key)
if err != nil {
t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
}
if !bytes.Equal(fvalue, tvalue) {
t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
}
}
}
@ -123,7 +150,7 @@ func TestIntermediateLeaks(t *testing.T) {
// https://github.com/ethereum/go-ethereum/pull/15549.
func TestCopy(t *testing.T) {
// Create a random state test to copy and modify "independently"
orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
@ -132,32 +159,45 @@ func TestCopy(t *testing.T) {
}
orig.Finalise(false)
// Copy the state, modify both in-memory
// Copy the state
copy := orig.Copy()
// Copy the copy state
ccopy := copy.Copy()
// modify all in memory
for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
origObj.AddBalance(big.NewInt(2 * int64(i)))
copyObj.AddBalance(big.NewInt(3 * int64(i)))
ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
orig.updateStateObject(origObj)
copy.updateStateObject(copyObj)
ccopy.updateStateObject(copyObj)
}
// Finalise the changes on both concurrently
done := make(chan struct{})
go func() {
orig.Finalise(true)
close(done)
}()
copy.Finalise(true)
<-done
// Verify that the two states have been updated independently
// Finalise the changes on all concurrently
finalise := func(wg *sync.WaitGroup, db *DB) {
defer wg.Done()
db.Finalise(true)
}
var wg sync.WaitGroup
wg.Add(3)
go finalise(&wg, orig)
go finalise(&wg, copy)
go finalise(&wg, ccopy)
wg.Wait()
// Verify that the three states have been updated independently
for i := byte(0); i < 255; i++ {
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
@ -165,6 +205,9 @@ func TestCopy(t *testing.T) {
if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
}
if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 {
t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want)
}
}
}
@ -179,7 +222,7 @@ func TestSnapshotRandom(t *testing.T) {
}
}
// A snapshotTest checks that reverting DB snapshots properly undoes all changes
// A snapshotTest checks that reverting StateDB snapshots properly undoes all changes
// captured by the snapshot. Instances of this test with pseudorandom content are created
// by Generate.
//
@ -277,13 +320,22 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
},
args: make([]int64, 1),
},
{
name: "AddPreimage",
fn: func(a testAction, s *DB) {
preimage := []byte{1}
hash := common.BytesToHash(preimage)
s.AddPreimage(hash, preimage)
},
args: make([]int64, 1),
},
}
action := actions[r.Intn(len(actions))]
var nameargs []string
if !action.noAddr {
nameargs = append(nameargs, common2.MustAddressToBech32(addr))
nameargs = append(nameargs, addr.Hex())
}
for _, i := range action.args {
for i := range action.args {
action.args[i] = rand.Int63n(100)
nameargs = append(nameargs, fmt.Sprint(action.args[i]))
}
@ -334,7 +386,7 @@ func (test *snapshotTest) String() string {
func (test *snapshotTest) run() bool {
// Run all actions and create snapshots.
var (
state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
snapshotRevs = make([]int, len(test.snapshots))
sindex = 0
)
@ -367,7 +419,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *DB) error {
var err error
checkeq := func(op string, a, b interface{}) bool {
if err == nil && !reflect.DeepEqual(a, b) {
err = fmt.Errorf("got %s(%s) == %v, want %v", op, common2.MustAddressToBech32(addr), a, b)
err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
return false
}
return true
@ -405,7 +457,8 @@ func (test *snapshotTest) checkEqual(state, checkstate *DB) error {
return nil
}
func (s *StateSuite) TestTouchDelete(c *check.C) {
func TestTouchDelete(t *testing.T) {
s := newStateTest()
s.state.GetOrNewStateObject(common.Address{})
root, _ := s.state.Commit(false)
s.state.Reset(root)
@ -414,25 +467,217 @@ func (s *StateSuite) TestTouchDelete(c *check.C) {
s.state.AddBalance(common.Address{}, new(big.Int))
if len(s.state.journal.dirties) != 1 {
c.Fatal("expected one dirty state object")
t.Fatal("expected one dirty state object")
}
s.state.RevertToSnapshot(snapshot)
if len(s.state.journal.dirties) != 0 {
c.Fatal("expected no dirty state object")
t.Fatal("expected no dirty state object")
}
}
// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
func TestCopyOfCopy(t *testing.T) {
sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
addr := common.HexToAddress("aaaa")
sdb.SetBalance(addr, big.NewInt(42))
state.SetBalance(addr, big.NewInt(42))
if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 {
if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
t.Fatalf("1st copy fail, expected 42, got %v", got)
}
if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
t.Fatalf("2nd copy fail, expected 42, got %v", got)
}
}
// Tests a regression where committing a copy lost some internal meta information,
// leading to corrupted subsequent copies.
//
// See https://github.com/ethereum/go-ethereum/issues/20106.
func TestCopyCommitCopy(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
// Create an account and check if the retrieved balance is correct
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
state.SetCode(addr, []byte("hello")) // Change an external metadata
state.SetState(addr, skey, sval) // Change the storage trie
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
}
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := state.GetState(addr, skey); val != sval {
t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
// Copy the non-committed state database and check pre/post commit balance
copyOne := state.Copy()
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
}
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyOne.GetState(addr, skey); val != sval {
t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
copyOne.Commit(false)
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42)
}
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyOne.GetState(addr, skey); val != sval {
t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyOne.GetCommittedState(addr, skey); val != sval {
t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
}
// Copy the copy and check the balance once more
copyTwo := copyOne.Copy()
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42)
}
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyTwo.GetState(addr, skey); val != sval {
t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyTwo.GetCommittedState(addr, skey); val != sval {
t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
}
}
// Tests a regression where committing a copy lost some internal meta information,
// leading to corrupted subsequent copies.
//
// See https://github.com/ethereum/go-ethereum/issues/20106.
func TestCopyCopyCommitCopy(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
// Create an account and check if the retrieved balance is correct
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
state.SetCode(addr, []byte("hello")) // Change an external metadata
state.SetState(addr, skey, sval) // Change the storage trie
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
}
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := state.GetState(addr, skey); val != sval {
t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
// Copy the non-committed state database and check pre/post commit balance
copyOne := state.Copy()
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42)
}
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyOne.GetState(addr, skey); val != sval {
t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
// Copy the copy and check the balance once more
copyTwo := copyOne.Copy()
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
}
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyTwo.GetState(addr, skey); val != sval {
t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) {
t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
copyTwo.Commit(false)
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42)
}
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyTwo.GetState(addr, skey); val != sval {
t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyTwo.GetCommittedState(addr, skey); val != sval {
t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
}
// Copy the copy-copy and check the balance once more
copyThree := copyTwo.Copy()
if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42)
}
if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello"))
}
if val := copyThree.GetState(addr, skey); val != sval {
t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval)
}
if val := copyThree.GetCommittedState(addr, skey); val != sval {
t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval)
}
}
// TestDeleteCreateRevert tests a weird state transition corner case that we hit
// while changing the internals of statedb. The workflow is that a contract is
// self destructed, then in a followup transaction (but same block) it's created
// again and the transaction reverted.
//
// The original statedb implementation flushed dirty objects to the tries after
// each transaction, so this works ok. The rework accumulated writes in memory
// first, but the journal wiped the entire state object on create-revert.
func TestDeleteCreateRevert(t *testing.T) {
// Create an initial state with a single contract
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
addr := toAddr([]byte("so"))
state.SetBalance(addr, big.NewInt(1))
root, _ := state.Commit(false)
state.Reset(root)
// Simulate self-destructing in one transaction, then create-reverting in another
state.Suicide(addr)
state.Finalise(true)
id := state.Snapshot()
state.SetBalance(addr, big.NewInt(2))
state.RevertToSnapshot(id)
// Commit the entire state and make sure we don't crash and have the correct state
root, _ = state.Commit(true)
state.Reset(root)
if state.getStateObject(addr) != nil {
t.Fatalf("self-destructed contract came alive")
}
}

@ -96,7 +96,7 @@ type Message interface {
}
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, contractCreation, homestead, isValidatorCreation bool) (uint64, error) {
func IntrinsicGas(data []byte, contractCreation, homestead, istanbul, isValidatorCreation bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
if contractCreation && homestead {
@ -116,10 +116,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead, isValidatorCreation
}
}
// Make sure we don't exceed uint64 for all data combinations
if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz {
nonZeroGas := params.TxDataNonZeroGasFrontier
if istanbul {
nonZeroGas = params.TxDataNonZeroGasEIP2028
}
if (math.MaxUint64-gas)/nonZeroGas < nz {
return 0, vm.ErrOutOfGas
}
gas += nz * params.TxDataNonZeroGas
gas += nz * nonZeroGas
z := uint64(len(data)) - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
@ -219,10 +223,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
msg := st.msg
sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsS3(st.evm.EpochNumber) // s3 includes homestead
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.EpochNumber)
contractCreation := msg.To() == nil
// Pay intrinsic gas
gas, err := IntrinsicGas(st.data, contractCreation, homestead, false)
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul, false)
if err != nil {
return nil, 0, false, err
}
@ -298,9 +303,10 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) {
sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsS3(st.evm.EpochNumber) // s3 includes homestead
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.EpochNumber)
// Pay intrinsic gas
gas, err := IntrinsicGas(st.data, false, homestead, msg.Type() == types.StakeCreateVal)
gas, err := IntrinsicGas(st.data, false, homestead, istanbul, msg.Type() == types.StakeCreateVal)
if err != nil {
return 0, err

@ -252,6 +252,7 @@ type TxPool struct {
txErrorSink *types.TransactionErrorSink // All failed txs gets reported here
homestead bool
istanbul bool
}
// NewTxPool creates a new transaction pool to gather, sort and filter inbound
@ -335,6 +336,9 @@ func (pool *TxPool) loop() {
if pool.chainconfig.IsS3(ev.Block.Epoch()) {
pool.homestead = true
}
if pool.chainconfig.IsIstanbul(ev.Block.Epoch()) {
pool.istanbul = true
}
pool.reset(head.Header(), ev.Block.Header())
head = ev.Block
pool.mu.Unlock()
@ -740,9 +744,9 @@ func (pool *TxPool) validateTx(tx types.PoolTransaction, local bool) error {
}
intrGas := uint64(0)
if isStakingTx {
intrGas, err = IntrinsicGas(tx.Data(), false, pool.homestead, stakingTx.StakingType() == staking.DirectiveCreateValidator)
intrGas, err = IntrinsicGas(tx.Data(), false, pool.homestead, pool.istanbul, stakingTx.StakingType() == staking.DirectiveCreateValidator)
} else {
intrGas, err = IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, false)
intrGas, err = IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.istanbul, false)
}
if err != nil {
return err

@ -26,11 +26,12 @@ import (
"testing"
"time"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
blockfactory "github.com/harmony-one/harmony/block/factory"
@ -153,7 +154,7 @@ func createBlockChain() *BlockChain {
GasLimit: 1e18,
ShardID: 0,
}
database := ethdb.NewMemDatabase()
database := rawdb.NewMemoryDatabase()
genesis := gspec.MustCommit(database)
_ = genesis
blockchain, _ := NewBlockChain(database, nil, gspec.Config, chain2.Engine, vm.Config{}, nil)
@ -161,7 +162,7 @@ func createBlockChain() *BlockChain {
}
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1e18, new(event.Feed)}
key, _ := crypto.GenerateKey()
@ -218,7 +219,7 @@ func (c *testChain) State() (*state.DB, error) {
// a state change between those fetches.
stdb := c.statedb
if *c.trigger {
c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
// simulate that the new head block included tx0 and tx1
c.statedb.SetNonce(c.address, 2)
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(denominations.One))
@ -236,7 +237,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
var (
key, _ = crypto.GenerateKey()
address = crypto.PubkeyToAddress(key.PublicKey)
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
trigger = false
)
@ -574,7 +575,7 @@ func TestTransactionChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@ -603,7 +604,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@ -799,7 +800,7 @@ func TestTransactionPostponing(t *testing.T) {
t.Parallel()
// Create the pool to test the postponing with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, dummyErrorSink)
@ -957,7 +958,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
t.Parallel()
// Create the pool to test the limit enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1047,7 +1048,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
evictionInterval = time.Second
// Create the pool to test the non-expiration enforcement
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1162,7 +1163,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1208,7 +1209,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1242,7 +1243,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1287,7 +1288,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, dummyErrorSink)
@ -1361,7 +1362,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
os.Remove(journal)
// Create the original pool to inject transaction into the journal
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@ -1459,7 +1460,7 @@ func TestTransactionStatusCheck(t *testing.T) {
t.Parallel()
// Create the pool to test the status retrievals with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain, dummyErrorSink)

@ -90,19 +90,17 @@ func (sink *TransactionErrorSink) Contains(hash string) bool {
func (sink *TransactionErrorSink) Remove(tx PoolTransaction) {
if plainTx, ok := tx.(*Transaction); ok {
hash := plainTx.Hash().String()
present := sink.failedPlainTxs.Remove(hash)
sink.failedPlainTxs.Remove(hash)
utils.Logger().Debug().
Str("tag", logTag).
Interface("tx-hash-id", hash).
Bool("was-in-error-sink", present).
Msgf("Removed plain transaction error message")
} else if stakingTx, ok := tx.(*staking.StakingTransaction); ok {
hash := stakingTx.Hash().String()
present := sink.failedStakingTxs.Remove(hash)
sink.failedStakingTxs.Remove(hash)
utils.Logger().Debug().
Str("tag", logTag).
Interface("tx-hash-id", hash).
Bool("was-in-error-sink", present).
Msgf("Removed staking transaction error message")
} else {
utils.Logger().Error().

@ -23,13 +23,31 @@ import (
"github.com/ethereum/go-ethereum/common/math"
)
// calculates the memory size required for a step
func calcMemSize(off, l *big.Int) *big.Int {
if l.Sign() == 0 {
return common.Big0
// calcMemSize64 calculates the required memory size, and returns
// the size and whether the result overflowed uint64
func calcMemSize64(off, l *big.Int) (uint64, bool) {
if !l.IsUint64() {
return 0, true
}
return calcMemSize64WithUint(off, l.Uint64())
}
return new(big.Int).Add(off, l)
// calcMemSize64WithUint calculates the required memory size, and returns
// the size and whether the result overflowed uint64
// Identical to calcMemSize64, but length is a uint64
func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
// if length is zero, memsize is always zero, regardless of offset
if length64 == 0 {
return 0, false
}
// Check that offset doesn't overflow
if !off.IsUint64() {
return 0, true
}
offset64 := off.Uint64()
val := offset64 + length64
// if value < either of it's parts, then it overflowed
return val, val < offset64
}
// getData returns a slice from the data based on the start and size and pads
@ -59,7 +77,7 @@ func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
// bigUint64 returns the integer casted to a uint64 and returns whether it
// overflowed in the process.
func bigUint64(v *big.Int) (uint64, bool) {
return v.Uint64(), v.BitLen() > 64
return v.Uint64(), !v.IsUint64()
}
// toWordSize returns the ceiled word size required for memory expansion.

@ -18,9 +18,12 @@ package vm
import (
"crypto/sha256"
"encoding/binary"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
@ -54,9 +57,23 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256Add{},
common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
common.BytesToAddress([]byte{8}): &bn256Pairing{},
common.BytesToAddress([]byte{6}): &bn256AddByzantium{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{},
common.BytesToAddress([]byte{8}): &bn256PairingByzantium{},
}
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release.
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
@ -90,8 +107,13 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) {
return nil, nil
}
// We must make sure not to modify the 'input', so placing the 'v' along with
// the signature needs to be done on a new allocation
sig := make([]byte, 65)
copy(sig, input[64:128])
sig[64] = v
// v needs to be at the end for libsecp256k1
pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v))
pubKey, err := crypto.Ecrecover(input[:32], sig)
// make sure the public key is a valid one
if err != nil {
return nil, nil
@ -271,15 +293,9 @@ func newTwistPoint(blob []byte) (*bn256.G2, error) {
return p, nil
}
// bn256Add implements a native elliptic curve point addition.
type bn256Add struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256Add) RequiredGas(input []byte) uint64 {
return params.Bn256AddGas
}
func (c *bn256Add) Run(input []byte) ([]byte, error) {
// runBn256Add implements the Bn256Add precompile, referenced by both
// Byzantium and Istanbul operations.
func runBn256Add(input []byte) ([]byte, error) {
x, err := newCurvePoint(getData(input, 0, 64))
if err != nil {
return nil, err
@ -293,15 +309,35 @@ func (c *bn256Add) Run(input []byte) ([]byte, error) {
return res.Marshal(), nil
}
// bn256ScalarMul implements a native elliptic curve scalar multiplication.
type bn256ScalarMul struct{}
// bn256Add implements a native elliptic curve point addition conforming to
// Istanbul consensus rules.
type bn256AddIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasIstanbul
}
func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
return runBn256Add(input)
}
// bn256AddByzantium implements a native elliptic curve point addition
// conforming to Byzantium consensus rules.
type bn256AddByzantium struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGas
func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasByzantium
}
func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) {
func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) {
return runBn256Add(input)
}
// runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by
// both Byzantium and Istanbul operations.
func runBn256ScalarMul(input []byte) ([]byte, error) {
p, err := newCurvePoint(getData(input, 0, 64))
if err != nil {
return nil, err
@ -311,6 +347,32 @@ func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) {
return res.Marshal(), nil
}
// bn256ScalarMulIstanbul implements a native elliptic curve scalar
// multiplication conforming to Istanbul consensus rules.
type bn256ScalarMulIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasIstanbul
}
func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
return runBn256ScalarMul(input)
}
// bn256ScalarMulByzantium implements a native elliptic curve scalar
// multiplication conforming to Byzantium consensus rules.
type bn256ScalarMulByzantium struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasByzantium
}
func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) {
return runBn256ScalarMul(input)
}
var (
// true32Byte is returned if the bn256 pairing check succeeds.
true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
@ -322,15 +384,9 @@ var (
errBadPairingInput = errors.New("bad elliptic curve pairing size")
)
// bn256Pairing implements a pairing pre-compile for the bn256 curve
type bn256Pairing struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256Pairing) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGas + uint64(len(input)/192)*params.Bn256PairingPerPointGas
}
func (c *bn256Pairing) Run(input []byte) ([]byte, error) {
// runBn256Pairing implements the Bn256Pairing precompile, referenced by both
// Byzantium and Istanbul operations.
func runBn256Pairing(input []byte) ([]byte, error) {
// Handle some corner cases cheaply
if len(input)%192 > 0 {
return nil, errBadPairingInput
@ -358,3 +414,90 @@ func (c *bn256Pairing) Run(input []byte) ([]byte, error) {
}
return false32Byte, nil
}
// bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve
// conforming to Istanbul consensus rules.
type bn256PairingIstanbul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
}
func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
return runBn256Pairing(input)
}
// bn256PairingByzantium implements a pairing pre-compile for the bn256 curve
// conforming to Byzantium consensus rules.
type bn256PairingByzantium struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium
}
func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) {
return runBn256Pairing(input)
}
type blake2F struct{}
func (c *blake2F) RequiredGas(input []byte) uint64 {
// If the input is malformed, we can't calculate the gas, return 0 and let the
// actual call choke and fault.
if len(input) != blake2FInputLength {
return 0
}
return uint64(binary.BigEndian.Uint32(input[0:4]))
}
const (
blake2FInputLength = 213
blake2FFinalBlockBytes = byte(1)
blake2FNonFinalBlockBytes = byte(0)
)
var (
errBlake2FInvalidInputLength = errors.New("invalid input length")
errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
)
func (c *blake2F) Run(input []byte) ([]byte, error) {
// Make sure the input is valid (correct lenth and final flag)
if len(input) != blake2FInputLength {
return nil, errBlake2FInvalidInputLength
}
if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes {
return nil, errBlake2FInvalidFinalFlag
}
// Parse the input into the Blake2b call parameters
var (
rounds = binary.BigEndian.Uint32(input[0:4])
final = (input[212] == blake2FFinalBlockBytes)
h [8]uint64
m [16]uint64
t [2]uint64
)
for i := 0; i < 8; i++ {
offset := 4 + i*8
h[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
}
for i := 0; i < 16; i++ {
offset := 68 + i*8
m[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
}
t[0] = binary.LittleEndian.Uint64(input[196:204])
t[1] = binary.LittleEndian.Uint64(input[204:212])
// Execute the compression function, extract and return the result
blake2b.F(&h, m, t, final, rounds)
output := make([]byte, 64)
for i := 0; i < 8; i++ {
offset := i * 8
binary.LittleEndian.PutUint64(output[offset:offset+8], h[i])
}
return output, nil
}

@ -17,8 +17,10 @@
package vm
import (
"bytes"
"fmt"
"math/big"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
@ -31,6 +33,14 @@ type precompiledTest struct {
noBenchmark bool // Benchmark primarily the worst-cases
}
// precompiledFailureTest defines the input/error pairs for precompiled
// contract failure tests.
type precompiledFailureTest struct {
input string
expectedError error
name string
}
// modexpTests are the test and benchmark data for the modexp precompiled contract.
var modexpTests = []precompiledTest{
{
@ -335,8 +345,61 @@ var bn256PairingTests = []precompiledTest{
},
}
// EIP-152 test vectors
var blake2FMalformedInputTests = []precompiledFailureTest{
{
input: "",
expectedError: errBlake2FInvalidInputLength,
name: "vector 0: empty input",
},
{
input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expectedError: errBlake2FInvalidInputLength,
name: "vector 1: less than 213 bytes input",
},
{
input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expectedError: errBlake2FInvalidInputLength,
name: "vector 2: more than 213 bytes input",
},
{
input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
expectedError: errBlake2FInvalidFinalFlag,
name: "vector 3: malformed final block indicator flag",
},
}
// EIP-152 test vectors
var blake2FTests = []precompiledTest{
{
input: "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expected: "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
name: "vector 4",
},
{ // https://tools.ietf.org/html/rfc7693#appendix-A
input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expected: "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
name: "vector 5",
},
{
input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000",
expected: "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
name: "vector 6",
},
{
input: "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expected: "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421",
name: "vector 7",
},
{
input: "007A120048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
expected: "6d2ce9e534d50e18ff866ae92d70cceba79bbcd14c63819fe48752c8aca87a4bb7dcc230d22a4047f0486cfcfb50a17b24b2899eb8fca370f22240adb5170189",
name: "vector 8",
},
}
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in))
@ -346,6 +409,48 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
} else if common.Bytes2Hex(res) != test.expected {
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
}
// Verify that the precompile did not touch the input buffer
exp := common.Hex2Bytes(test.input)
if !bytes.Equal(in, exp) {
t.Errorf("Precompiled %v modified input data", addr)
}
})
}
func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in)-1)
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
_, err := RunPrecompiledContract(p, in, contract)
if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err)
}
// Verify that the precompile did not touch the input buffer
exp := common.Hex2Bytes(test.input)
if !bytes.Equal(in, exp) {
t.Errorf("Precompiled %v modified input data", addr)
}
})
}
func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("31337")),
nil, new(big.Int), p.RequiredGas(in))
t.Run(test.name, func(t *testing.T) {
_, err := RunPrecompiledContract(p, in, contract)
if !reflect.DeepEqual(err, test.expectedError) {
t.Errorf("Expected error [%v], got [%v]", test.expectedError, err)
}
// Verify that the precompile did not touch the input buffer
exp := common.Hex2Bytes(test.input)
if !bytes.Equal(in, exp) {
t.Errorf("Precompiled %v modified input data", addr)
}
})
}
@ -353,7 +458,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
if test.noBenchmark {
return
}
p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
reqGas := p.RequiredGas(in)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
@ -453,6 +558,13 @@ func BenchmarkPrecompiledBn256Add(bench *testing.B) {
}
}
// Tests OOG
func TestPrecompiledModExpOOG(t *testing.T) {
for _, test := range modexpTests {
testPrecompiledOOG("05", test, t)
}
}
// Tests the sample inputs from the elliptic curve scalar multiplication EIP 213.
func TestPrecompiledBn256ScalarMul(t *testing.T) {
for _, test := range bn256ScalarMulTests {
@ -480,3 +592,72 @@ func BenchmarkPrecompiledBn256Pairing(bench *testing.B) {
benchmarkPrecompiled("08", test, bench)
}
}
func TestPrecompiledBlake2F(t *testing.T) {
for _, test := range blake2FTests {
testPrecompiled("09", test, t)
}
}
func BenchmarkPrecompiledBlake2F(bench *testing.B) {
for _, test := range blake2FTests {
benchmarkPrecompiled("09", test, bench)
}
}
func TestPrecompileBlake2FMalformedInput(t *testing.T) {
for _, test := range blake2FMalformedInputTests {
testPrecompiledFailure("09", test, t)
}
}
// EcRecover test vectors
var ecRecoverTests = []precompiledTest{
{
input: "a8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281" +
"000000000000000000000000000000000000000000000000000000000000001b" +
"3078356531653033663533636531386237373263636230303933666637316633" +
"6635336635633735623734646362333161383561613862383839326234653862" +
"1122334455667788991011121314151617181920212223242526272829303132",
expected: "",
name: "CallEcrecoverUnrecoverableKey",
},
{
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
"000000000000000000000000000000000000000000000000000000000000001c" +
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
expected: "000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
name: "ValidKey",
},
{
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
"100000000000000000000000000000000000000000000000000000000000001c" +
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
expected: "",
name: "InvalidHighV-bits-1",
},
{
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
"000000000000000000000000000000000000001000000000000000000000001c" +
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
expected: "",
name: "InvalidHighV-bits-2",
},
{
input: "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" +
"000000000000000000000000000000000000001000000000000000000000011c" +
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f" +
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549",
expected: "",
name: "InvalidHighV-bits-3",
},
}
func TestPrecompiledEcrecover(t *testing.T) {
for _, test := range ecRecoverTests {
testPrecompiled("01", test, t)
}
}

@ -0,0 +1,92 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm
import (
"fmt"
"github.com/harmony-one/harmony/internal/params"
)
// EnableEIP enables the given EIP on the config.
// This operation writes in-place, and callers need to ensure that the globally
// defined jump tables are not polluted.
func EnableEIP(eipNum int, jt *JumpTable) error {
switch eipNum {
case 2200:
enable2200(jt)
case 1884:
enable1884(jt)
case 1344:
enable1344(jt)
default:
return fmt.Errorf("undefined eip %d", eipNum)
}
return nil
}
// enable1884 applies EIP-1884 to the given jump table:
// - Increase cost of BALANCE to 700
// - Increase cost of EXTCODEHASH to 700
// - Increase cost of SLOAD to 800
// - Define SELFBALANCE, with cost GasFastStep (5)
func enable1884(jt *JumpTable) {
// Gas cost changes
jt[BALANCE].constantGas = params.BalanceGasEIP1884
jt[EXTCODEHASH].constantGas = params.ExtcodeHashGasEIP1884
jt[SLOAD].constantGas = params.SloadGasEIP1884
// New opcode
jt[SELFBALANCE] = operation{
execute: opSelfBalance,
constantGas: GasFastStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true,
}
}
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()))
stack.push(balance)
return nil, nil
}
// enable1344 applies EIP-1344 (ChainID Opcode)
// - Adds an opcode that returns the current chain’s EIP-155 unique identifier
func enable1344(jt *JumpTable) {
// New opcode
jt[CHAINID] = operation{
execute: opChainID,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true,
}
}
// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
chainID := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID)
stack.push(chainID)
return nil, nil
}
// enable2200 applies EIP-2200 (Rebalance net-metered SSTORE)
func enable2200(jt *JumpTable) {
jt[SSTORE].dynamicGas = gasSStoreEIP2200
}

@ -51,6 +51,9 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
if evm.ChainConfig().IsS3(evm.EpochNumber) {
precompiles = PrecompiledContractsByzantium
}
if evm.chainRules.IsIstanbul {
precompiles = PrecompiledContractsIstanbul
}
if p := precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract)
}
@ -219,6 +222,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if evm.ChainConfig().IsS3(evm.EpochNumber) {
precompiles = PrecompiledContractsByzantium
}
if evm.chainRules.IsIstanbul {
precompiles = PrecompiledContractsIstanbul
}
if precompiles[addr] == nil && evm.ChainConfig().IsS3(evm.EpochNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 {

@ -18,8 +18,6 @@ package vm
import (
"math/big"
"github.com/harmony-one/harmony/internal/params"
)
// Gas costs
@ -30,28 +28,24 @@ const (
GasMidStep uint64 = 8
GasSlowStep uint64 = 10
GasExtStep uint64 = 20
GasReturn uint64 = 0
GasStop uint64 = 0
GasContractByte uint64 = 200
)
// calcGas returns the actual gas cost of the call.
//
// The cost of gas was changed during the homestead price change HF. To allow for EIP150
// to be implemented. The returned gas is gas - base * 63 / 64.
func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
if gasTable.CreateBySuicide > 0 {
// The cost of gas was changed during the homestead price change HF.
// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64.
func callGas(isEip150 bool, availableGas, base uint64, callCost *big.Int) (uint64, error) {
if isEip150 {
availableGas = availableGas - base
gas := availableGas - availableGas/64
// If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
// is smaller than the requested amount. Therefor we return the new gas instead
// of returning an error.
if callCost.BitLen() > 64 || gas < callCost.Uint64() {
if !callCost.IsUint64() || gas < callCost.Uint64() {
return gas, nil
}
}
if callCost.BitLen() > 64 {
if !callCost.IsUint64() {
return 0, errGasUintOverflow
}

@ -17,29 +17,27 @@
package vm
import (
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/harmony-one/harmony/internal/params"
)
// memoryGasCosts calculates the quadratic gas for memory expansion. It does so
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
// only for the memory region that is expanded, not the total memory.
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
if newMemSize == 0 {
return 0, nil
}
// The maximum that will fit in a uint64 is max_word_count - 1
// anything above that will result in an overflow.
// Additionally, a newMemSize which results in a
// newMemSizeWords larger than 0x7ffffffff will cause the square operation
// to overflow.
// The constant 0xffffffffe0 is the highest number that can be used without
// overflowing the gas calculation
if newMemSize > 0xffffffffe0 {
// The maximum that will fit in a uint64 is max_word_count - 1. Anything above
// that will result in an overflow. Additionally, a newMemSize which results in
// a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to
// overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used
// without overflowing the gas calculation.
if newMemSize > 0x1FFFFFFFE0 {
return 0, errGasUintOverflow
}
newMemSizeWords := toWordSize(newMemSize)
newMemSize = newMemSizeWords * 32
@ -57,65 +55,45 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
return 0, nil
}
func constGasFunc(gas uint64) gasFunc {
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gas, nil
}
}
func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
words, overflow := bigUint64(stack.Back(2))
if overflow {
return 0, errGasUintOverflow
}
// memoryCopierGas creates the gas functions for the following opcodes, and takes
// the stack position of the operand which determines the size of the data to copy
// as argument:
// CALLDATACOPY (stack position 2)
// CODECOPY (stack position 2)
// EXTCODECOPY (stack poition 3)
// RETURNDATACOPY (stack position 2)
func memoryCopierGas(stackpos int) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
// Gas for expanding the memory
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
// And gas for copying data, charged per word at param.CopyGas
words, overflow := bigUint64(stack.Back(stackpos))
if overflow {
return 0, errGasUintOverflow
}
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, words); overflow {
return 0, errGasUintOverflow
if gas, overflow = math.SafeAdd(gas, words); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
return gas, nil
}
func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
words, overflow := bigUint64(stack.Back(2))
if overflow {
return 0, errGasUintOverflow
}
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, words); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
var (
gasCallDataCopy = memoryCopierGas(2)
gasCodeCopy = memoryCopierGas(2)
gasExtCodeCopy = memoryCopierGas(3)
gasReturnDataCopy = memoryCopierGas(2)
)
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
y, x = stack.Back(1), stack.Back(0)
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
@ -184,8 +162,63 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
return params.NetSstoreDirtyGas, nil
}
// 0. If *gasleft* is less than or equal to 2300, fail the current call.
// 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS gas is deducted.
// 2. If current value does not equal new value:
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context):
// 2.1.1. If original value is 0, SSTORE_INIT_GAS gas is deducted.
// 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter.
// 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses:
// 2.2.1. If original value is not 0:
// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEAR_REFUND gas from refund counter. We can prove that refund counter will never go below 0.
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEAR_REFUND gas to refund counter.
// 2.2.2. If original value equals new value (this storage slot is reset):
// 2.2.2.1. If original value is 0, add SSTORE_INIT_REFUND to refund counter.
// 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND gas to refund counter.
func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
// If we fail the minimum gas availability invariant, fail (0)
if contract.Gas <= params.SstoreSentryGasEIP2200 {
return 0, errors.New("not enough gas for reentrancy sentry")
}
// Gas sentry honoured, do the actual gas calculation based on the stored value
var (
y, x = stack.Back(1), stack.Back(0)
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
)
value := common.BigToHash(y)
if current == value { // noop (1)
return params.SstoreNoopGasEIP2200, nil
}
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
if original == current {
if original == (common.Hash{}) { // create slot (2.1.1)
return params.SstoreInitGasEIP2200, nil
}
if value == (common.Hash{}) { // delete slot (2.1.2b)
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
}
return params.SstoreCleanGasEIP2200, nil // write existing slot (2.1.2)
}
if original != (common.Hash{}) {
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
evm.StateDB.SubRefund(params.SstoreClearRefundEIP2200)
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
}
}
if original == value {
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200)
} else { // reset to original existing slot (2.2.2.2)
evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200)
}
}
return params.SstoreDirtyGasEIP2200, nil // dirty update (2.2)
}
func makeGasLog(n uint64) gasFunc {
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
requestedSize, overflow := bigUint64(stack.Back(1))
if overflow {
return 0, errGasUintOverflow
@ -214,17 +247,11 @@ func makeGasLog(n uint64) gasFunc {
}
}
func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(1))
if overflow {
return 0, errGasUintOverflow
@ -238,117 +265,27 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
return gas, nil
}
func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(2))
if overflow {
return 0, errGasUintOverflow
}
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(3))
if overflow {
return 0, errGasUintOverflow
}
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.ExtcodeHash, nil
}
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, errGasUintOverflow
}
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
return 0, errGasUintOverflow
}
return gas, nil
// pureMemoryGascost is used by several operations, which aside from their
// static cost have a dynamic cost which is solely based on the memory
// expansion
func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize)
}
func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
var (
gasReturn = pureMemoryGascost
gasRevert = pureMemoryGascost
gasMLoad = pureMemoryGascost
gasMStore8 = pureMemoryGascost
gasMStore = pureMemoryGascost
gasCreate = pureMemoryGascost
)
func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var overflow bool
func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow {
return 0, errGasUintOverflow
}
wordGas, overflow := bigUint64(stack.Back(2))
if overflow {
return 0, errGasUintOverflow
@ -359,43 +296,42 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.Balance, nil
}
func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.ExtcodeSize, nil
}
func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return gt.SLoad, nil
var (
gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas
overflow bool
)
if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
var (
gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas
overflow bool
)
if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var (
gas = gt.Calls
gas uint64
transfersValue = stack.Back(2).Sign() != 0
address = common.BigToAddress(stack.Back(1))
eip158 = evm.ChainConfig().IsS3(evm.EpochNumber)
)
if eip158 {
if evm.chainRules.IsS3 {
if transfersValue && evm.StateDB.Empty(address) {
gas += params.CallNewAccountGas
}
@ -414,7 +350,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
return 0, errGasUintOverflow
}
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
evm.callGasTemp, err = callGas(evm.chainRules.IsS3, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
}
@ -424,21 +360,22 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
return gas, nil
}
func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas := gt.Calls
if stack.Back(2).Sign() != 0 {
gas += params.CallValueTransferGas
}
func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
memoryGas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
var (
gas uint64
overflow bool
)
if stack.Back(2).Sign() != 0 {
gas += params.CallValueTransferGas
}
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
return 0, errGasUintOverflow
}
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
evm.callGasTemp, err = callGas(evm.chainRules.IsS3, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
}
@ -448,88 +385,57 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
return gas, nil
}
func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize)
}
func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return memoryGasCost(mem, memorySize)
}
func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var gas uint64
// EIP150 homestead gas reprice fork:
if evm.ChainConfig().IsS3(evm.EpochNumber) {
gas = gt.Suicide
var (
address = common.BigToAddress(stack.Back(0))
eip158 = evm.ChainConfig().IsS3(evm.EpochNumber)
)
if eip158 {
// if empty and transfers value
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
gas += gt.CreateBySuicide
}
} else if !evm.StateDB.Exist(address) {
gas += gt.CreateBySuicide
}
}
if !evm.StateDB.HasSuicided(contract.Address()) {
evm.StateDB.AddRefund(params.SuicideRefundGas)
}
return gas, nil
}
func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
return 0, errGasUintOverflow
}
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
evm.callGasTemp, err = callGas(evm.chainRules.IsS3, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
return 0, errGasUintOverflow
}
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
evm.callGasTemp, err = callGas(evm.chainRules.IsS3, contract.Gas, gas, stack.Back(0))
if err != nil {
return 0, err
}
var overflow bool
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
return 0, errGasUintOverflow
}
return gas, nil
}
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return GasFastestStep, nil
}
func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
var gas uint64
// EIP150 homestead gas reprice fork:
if evm.chainRules.IsS3 {
gas = params.SelfdestructGasEIP150
var address = common.BigToAddress(stack.Back(0))
func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return GasFastestStep, nil
}
if evm.chainRules.IsS3 {
// if empty and transfers value
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
gas += params.CreateBySelfdestructGas
}
} else if !evm.StateDB.Exist(address) {
gas += params.CreateBySelfdestructGas
}
}
func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
return GasFastestStep, nil
if !evm.StateDB.HasSuicided(contract.Address()) {
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
}
return gas, nil
}

@ -16,21 +16,95 @@
package vm
import "testing"
import (
"math"
"math/big"
"testing"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/core/state"
)
func TestMemoryGasCost(t *testing.T) {
//size := uint64(math.MaxUint64 - 64)
size := uint64(0xffffffffe0)
v, err := memoryGasCost(&Memory{}, size)
if err != nil {
t.Error("didn't expect error:", err)
tests := []struct {
size uint64
cost uint64
overflow bool
}{
{0x1fffffffe0, 36028809887088637, false},
{0x1fffffffe1, 0, true},
}
if v != 36028899963961341 {
t.Errorf("Expected: 36028899963961341, got %d", v)
for i, tt := range tests {
v, err := memoryGasCost(&Memory{}, tt.size)
if (err == errGasUintOverflow) != tt.overflow {
t.Errorf("test %d: overflow mismatch: have %v, want %v", i, err == errGasUintOverflow, tt.overflow)
}
if v != tt.cost {
t.Errorf("test %d: gas cost mismatch: have %v, want %v", i, v, tt.cost)
}
}
}
var eip2200Tests = []struct {
original byte
gaspool uint64
input string
used uint64
refund uint64
failure error
}{
{0, math.MaxUint64, "0x60006000556000600055", 1612, 0, nil}, // 0 -> 0 -> 0
{0, math.MaxUint64, "0x60006000556001600055", 20812, 0, nil}, // 0 -> 0 -> 1
{0, math.MaxUint64, "0x60016000556000600055", 20812, 19200, nil}, // 0 -> 1 -> 0
{0, math.MaxUint64, "0x60016000556002600055", 20812, 0, nil}, // 0 -> 1 -> 2
{0, math.MaxUint64, "0x60016000556001600055", 20812, 0, nil}, // 0 -> 1 -> 1
{1, math.MaxUint64, "0x60006000556000600055", 5812, 15000, nil}, // 1 -> 0 -> 0
{1, math.MaxUint64, "0x60006000556001600055", 5812, 4200, nil}, // 1 -> 0 -> 1
{1, math.MaxUint64, "0x60006000556002600055", 5812, 0, nil}, // 1 -> 0 -> 2
{1, math.MaxUint64, "0x60026000556000600055", 5812, 15000, nil}, // 1 -> 2 -> 0
{1, math.MaxUint64, "0x60026000556003600055", 5812, 0, nil}, // 1 -> 2 -> 3
{1, math.MaxUint64, "0x60026000556001600055", 5812, 4200, nil}, // 1 -> 2 -> 1
{1, math.MaxUint64, "0x60026000556002600055", 5812, 0, nil}, // 1 -> 2 -> 2
{1, math.MaxUint64, "0x60016000556000600055", 5812, 15000, nil}, // 1 -> 1 -> 0
{1, math.MaxUint64, "0x60016000556002600055", 5812, 0, nil}, // 1 -> 1 -> 2
{1, math.MaxUint64, "0x60016000556001600055", 1612, 0, nil}, // 1 -> 1 -> 1
{0, math.MaxUint64, "0x600160005560006000556001600055", 40818, 19200, nil}, // 0 -> 1 -> 0 -> 1
{1, math.MaxUint64, "0x600060005560016000556000600055", 10818, 19200, nil}, // 1 -> 0 -> 1 -> 0
{1, 2306, "0x6001600055", 2306, 0, ErrOutOfGas}, // 1 -> 1 (2300 sentry + 2xPUSH)
{1, 2307, "0x6001600055", 806, 0, nil}, // 1 -> 1 (2301 sentry + 2xPUSH)
}
func TestEIP2200(t *testing.T) {
for i, tt := range eip2200Tests {
address := common.BytesToAddress([]byte("contract"))
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb.CreateAccount(address)
statedb.SetCode(address, hexutil.MustDecode(tt.input))
statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original}))
statedb.Finalise(true) // Push the state into the "original" slot
vmctx := Context{
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *big.Int, types.TransactionType) {},
IsValidator: func(StateDB, common.Address) bool { return false },
}
vmenv := NewEVM(vmctx, statedb, params.AllProtocolChanges, Config{ExtraEips: []int{2200}})
_, err = memoryGasCost(&Memory{}, size+1)
if err == nil {
t.Error("expected error")
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int))
if err != tt.failure {
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
}
if used := tt.gaspool - gas; used != tt.used {
t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used)
}
if refund := vmenv.StateDB.GetRefund(); refund != tt.refund {
t.Errorf("test %d: gas refund mismatch: have %v, want %v", i, refund, tt.refund)
}
}
}

@ -18,7 +18,6 @@ package vm
import (
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -35,6 +34,7 @@ var (
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
errExecutionReverted = errors.New("evm: execution reverted")
errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
errInvalidJump = errors.New("evm: invalid jump destination")
)
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@ -384,7 +384,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset, size := stack.pop(), stack.pop()
data := memory.Get(offset.Int64(), size.Int64())
data := memory.GetPtr(offset.Int64(), size.Int64())
if interpreter.hasher == nil {
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
@ -405,7 +405,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
}
func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(contract.Address().Big())
stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes()))
return nil, nil
}
@ -416,12 +416,12 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
}
func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.evm.Origin.Big())
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil
}
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(contract.Caller().Big())
stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes()))
return nil, nil
}
@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
)
defer interpreter.intPool.put(memOffset, dataOffset, length, end)
if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() {
if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
return nil, errReturnDataOutOfBounds
}
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
@ -572,7 +572,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, me
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(interpreter.evm.Coinbase.Big())
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
return nil, nil
}
@ -587,7 +587,6 @@ func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
}
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// TODO: remove this op (add other ops like rand)
stack.push(math.U256(interpreter.intPool.get().Set(big.NewInt(0))))
return nil, nil
}
@ -603,11 +602,9 @@ func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
}
func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset := stack.pop()
val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
stack.push(val)
interpreter.intPool.put(offset)
v := stack.peek()
offset := v.Int64()
v.SetBytes(memory.GetPtr(offset, 32))
return nil, nil
}
@ -646,8 +643,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos := stack.pop()
if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
return nil, errInvalidJump
}
*pc = pos.Uint64()
@ -659,8 +655,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
pos, cond := stack.pop(), stack.pop()
if cond.Sign() != 0 {
if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64())
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
return nil, errInvalidJump
}
*pc = pos.Uint64()
} else {
@ -694,7 +689,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
var (
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = memory.Get(offset.Int64(), size.Int64())
input = memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas
)
if interpreter.evm.ChainConfig().IsS3(interpreter.evm.EpochNumber) {
@ -712,7 +707,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero())
} else {
stack.push(addr.Big())
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
}
contract.Gas += returnGas
interpreter.intPool.put(value, offset, size)
@ -728,7 +723,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
endowment = stack.pop()
offset, size = stack.pop(), stack.pop()
salt = stack.pop()
input = memory.Get(offset.Int64(), size.Int64())
input = memory.GetCopy(offset.Int64(), size.Int64())
gas = contract.Gas
)
@ -740,7 +735,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
if suberr != nil {
stack.push(interpreter.intPool.getZero())
} else {
stack.push(addr.Big())
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
}
contract.Gas += returnGas
interpreter.intPool.put(endowment, offset, size, salt)
@ -760,7 +755,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
toAddr := common.BigToAddress(addr)
value = math.U256(value)
// Get the arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 {
gas += params.CallStipend
@ -789,7 +784,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
toAddr := common.BigToAddress(addr)
value = math.U256(value)
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
if value.Sign() != 0 {
gas += params.CallStipend
@ -817,7 +812,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas)
if err != nil {
@ -842,7 +837,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.BigToAddress(addr)
// Get arguments from the memory.
args := memory.Get(inOffset.Int64(), inSize.Int64())
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas)
if err != nil {
@ -898,7 +893,7 @@ func makeLog(size int) executionFunc {
topics[i] = common.BigToHash(stack.pop())
}
d := memory.Get(mStart.Int64(), mSize.Int64())
d := memory.GetCopy(mStart.Int64(), mSize.Int64())
interpreter.evm.StateDB.AddLog(&types.Log{
Address: contract.Address(),
Topics: topics,
@ -913,6 +908,21 @@ func makeLog(size int) executionFunc {
}
}
// opPush1 is a specialized version of pushN
func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
var (
codeLen = uint64(len(contract.Code))
integer = interpreter.intPool.get()
)
*pc++
if *pc < codeLen {
stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
} else {
stack.push(integer.SetUint64(0))
}
return nil, nil
}
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {

@ -18,6 +18,9 @@ package vm
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"testing"
@ -26,32 +29,91 @@ import (
"github.com/harmony-one/harmony/internal/params"
)
type twoOperandTest struct {
x string
y string
expected string
type TwoOperandTestcase struct {
X string
Y string
Expected string
}
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
type twoOperandParams struct {
x string
y string
}
var commonParams []*twoOperandParams
var twoOpMethods map[string]executionFunc
func init() {
// Params is a list of common edgecases that should be used for some common tests
params := []string{
"0000000000000000000000000000000000000000000000000000000000000000", // 0
"0000000000000000000000000000000000000000000000000000000000000001", // +1
"0000000000000000000000000000000000000000000000000000000000000005", // +5
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", // + max -1
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // + max
"8000000000000000000000000000000000000000000000000000000000000000", // - max
"8000000000000000000000000000000000000000000000000000000000000001", // - max+1
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", // - 5
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // - 1
}
// Params are combined so each param is used on each 'side'
commonParams = make([]*twoOperandParams, len(params)*len(params))
for i, x := range params {
for j, y := range params {
commonParams[i*len(params)+j] = &twoOperandParams{x, y}
}
}
twoOpMethods = map[string]executionFunc{
"add": opAdd,
"sub": opSub,
"mul": opMul,
"div": opDiv,
"sdiv": opSdiv,
"mod": opMod,
"smod": opSmod,
"exp": opExp,
"signext": opSignExtend,
"lt": opLt,
"gt": opGt,
"slt": opSlt,
"sgt": opSgt,
"eq": opEq,
"and": opAnd,
"or": opOr,
"xor": opXor,
"byte": opByte,
"shl": opSHL,
"shr": opSHR,
"sar": opSAR,
}
}
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
evmInterpreter = env.interpreter.(*EVMInterpreter)
)
env.interpreter = evmInterpreter
// Stuff a couple of nonzero bigints into pool, to ensure that ops do not rely on pooled integers to be zero
evmInterpreter.intPool = poolOfIntPools.get()
evmInterpreter.intPool.put(big.NewInt(-1337))
evmInterpreter.intPool.put(big.NewInt(-1337))
evmInterpreter.intPool.put(big.NewInt(-1337))
for i, test := range tests {
x := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y))
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected))
x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
stack.push(shift)
stack.push(y)
opFn(&pc, evmInterpreter, nil, nil, stack)
actual := stack.pop()
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual)
t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
}
// Check pool usage
// 1.pool is not allowed to contain anything on the stack
@ -64,7 +126,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
for evmInterpreter.intPool.pool.len() > 0 {
key := evmInterpreter.intPool.get()
if _, exist := poolvals[key]; exist {
t.Errorf("Testcase %d, pool contains double-entry", i)
t.Errorf("Testcase %v %d, pool contains double-entry", name, i)
}
poolvals[key] = struct{}{}
}
@ -74,47 +136,22 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
}
func TestByteOp(t *testing.T) {
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
)
env.interpreter = evmInterpreter
evmInterpreter.intPool = poolOfIntPools.get()
tests := []struct {
v string
th uint64
expected *big.Int
}{
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 0, big.NewInt(0xAB)},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 1, big.NewInt(0xCD)},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 0, big.NewInt(0x00)},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 1, big.NewInt(0xCD)},
{"0000000000000000000000000000000000000000000000000000000000102030", 31, big.NewInt(0x30)},
{"0000000000000000000000000000000000000000000000000000000000102030", 30, big.NewInt(0x20)},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32, big.NewInt(0x0)},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0xFFFFFFFFFFFFFFFF, big.NewInt(0x0)},
tests := []TwoOperandTestcase{
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", "00", "AB"},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", "01", "CD"},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", "00", "00"},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", "01", "CD"},
{"0000000000000000000000000000000000000000000000000000000000102030", "1F", "30"},
{"0000000000000000000000000000000000000000000000000000000000102030", "1E", "20"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "20", "00"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "FFFFFFFFFFFFFFFF", "00"},
}
pc := uint64(0)
for _, test := range tests {
val := new(big.Int).SetBytes(common.Hex2Bytes(test.v))
th := new(big.Int).SetUint64(test.th)
stack.push(val)
stack.push(th)
opByte(&pc, evmInterpreter, nil, nil, stack)
actual := stack.pop()
if actual.Cmp(test.expected) != 0 {
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual)
}
}
poolOfIntPools.put(evmInterpreter.intPool)
testTwoOperandOp(t, tests, opByte, "byte")
}
func TestSHL(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
@ -126,12 +163,12 @@ func TestSHL(t *testing.T) {
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
}
testTwoOperandOp(t, tests, opSHL)
testTwoOperandOp(t, tests, opSHL, "shl")
}
func TestSHR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right
tests := []twoOperandTest{
tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "4000000000000000000000000000000000000000000000000000000000000000"},
@ -144,12 +181,12 @@ func TestSHR(t *testing.T) {
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
}
testTwoOperandOp(t, tests, opSHR)
testTwoOperandOp(t, tests, opSHR, "shr")
}
func TestSAR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right
tests := []twoOperandTest{
tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "c000000000000000000000000000000000000000000000000000000000000000"},
@ -168,44 +205,59 @@ func TestSAR(t *testing.T) {
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
}
testTwoOperandOp(t, tests, opSAR)
testTwoOperandOp(t, tests, opSAR, "sar")
}
func TestSGT(t *testing.T) {
tests := []twoOperandTest{
// getResult is a convenience function to generate the expected values
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
interpreter = env.interpreter.(*EVMInterpreter)
)
interpreter.intPool = poolOfIntPools.get()
result := make([]TwoOperandTestcase, len(args))
for i, param := range args {
x := new(big.Int).SetBytes(common.Hex2Bytes(param.x))
y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
stack.push(x)
stack.push(y)
opFn(&pc, interpreter, nil, nil, stack)
actual := stack.pop()
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
}
return result
}
// utility function to fill the json-file with testcases
// Enable this test to generate the 'testcases_xx.json' files
func TestWriteExpectedValues(t *testing.T) {
t.Skip("Enable this test to create json test cases.")
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"},
for name, method := range twoOpMethods {
data, err := json.Marshal(getResult(commonParams, method))
if err != nil {
t.Fatal(err)
}
_ = ioutil.WriteFile(fmt.Sprintf("testdata/testcases_%v.json", name), data, 0644)
if err != nil {
t.Fatal(err)
}
}
testTwoOperandOp(t, tests, opSgt)
}
func TestSLT(t *testing.T) {
tests := []twoOperandTest{
{"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
{"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"},
{"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"},
}
// TestJsonTestcases runs through all the testcases defined as json-files
func TestJsonTestcases(t *testing.T) {
for name := range twoOpMethods {
data, err := ioutil.ReadFile(fmt.Sprintf("testdata/testcases_%v.json", name))
if err != nil {
t.Fatal("Failed to read file", err)
}
var testcases []TwoOperandTestcase
json.Unmarshal(data, &testcases)
testTwoOperandOp(t, testcases, twoOpMethods[name], name)
}
testTwoOperandOp(t, tests, opSlt)
}
func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
@ -458,12 +510,12 @@ func TestOpMstore(t *testing.T) {
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
opMstore(&pc, evmInterpreter, nil, mem, stack)
if got := common.Bytes2Hex(mem.Get(0, 32)); got != v {
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
}
stack.pushN(big.NewInt(0x1), big.NewInt(0))
opMstore(&pc, evmInterpreter, nil, mem, stack)
if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
t.Fatalf("Mstore failed to overwrite previous value")
}
poolOfIntPools.put(evmInterpreter.intPool)

@ -73,7 +73,7 @@ type StateDB interface {
AddLog(*types.Log)
AddPreimage(common.Hash, []byte)
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
}
// CallContext provides a basic interface for the EVM calling conventions. The EVM

@ -21,9 +21,10 @@ import (
"hash"
"sync/atomic"
"github.com/harmony-one/harmony/internal/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/harmony-one/harmony/internal/params"
)
// Config are the configuration options for the Interpreter
@ -46,6 +47,9 @@ type Config struct {
EWASMInterpreter string
// Type of the EVM interpreter
EVMInterpreter string
// ExtraEips the additional EIPS that are to be enabled
ExtraEips []int
}
// Interpreter is used to run Ethereum based contracts and will utilise the
@ -80,9 +84,8 @@ type keccakState interface {
// EVMInterpreter represents an EVM interpreter
type EVMInterpreter struct {
evm *EVM
cfg Config
gasTable params.GasTable
evm *EVM
cfg Config
intPool *intPool
@ -99,40 +102,29 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// the jump table was initialised. If it was not
// we'll set the default jump table.
if !cfg.JumpTable[STOP].valid {
//switch {
//case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
// cfg.JumpTable = constantinopleInstructionSet
//case evm.ChainConfig().IsByzantium(evm.BlockNumber):
// cfg.JumpTable = byzantiumInstructionSet
//case evm.ChainConfig().IsHomestead(evm.BlockNumber):
// cfg.JumpTable = homesteadInstructionSet
//default:
// cfg.JumpTable = frontierInstructionSet
//}
cfg.JumpTable = constantinopleInstructionSet
var jt JumpTable
switch {
case evm.chainRules.IsIstanbul:
jt = istanbulInstructionSet
case evm.chainRules.IsS3:
jt = constantinopleInstructionSet
default:
jt = frontierInstructionSet
}
for i, eip := range cfg.ExtraEips {
if err := EnableEIP(eip, &jt); err != nil {
// Disable it, so caller can check if it's activated or not
cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...)
utils.Logger().Error().Int("eip", eip).Err(err).Msg("EIP activation failed")
}
}
cfg.JumpTable = jt
}
return &EVMInterpreter{
evm: evm,
cfg: cfg,
gasTable: evm.ChainConfig().GasTable(evm.EpochNumber),
}
}
func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
if in.evm.chainRules.IsS3 {
if in.readOnly {
// If the interpreter is operating in readonly mode, make sure no
// state-modifying operation is performed. The 3rd stack item
// for a call operation is the value. Transferring value from one
// account to the others means the state is modified and should also
// return with an error.
if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) {
return errWriteProtection
}
}
evm: evm,
cfg: cfg,
}
return nil
}
// Run loops and evaluates the contract's code with the given input data and returns
@ -183,6 +175,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
pcCopy uint64 // needed for the deferred Tracer
gasCopy uint64 // for Tracer to log gas remaining before execution
logged bool // deferred Tracer should ignore already logged steps
res []byte // result of the opcode execution function
)
contract.Input = input
@ -217,19 +210,36 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if !operation.valid {
return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
}
if err := operation.validateStack(stack); err != nil {
return nil, err
// Validate stack
if sLen := stack.len(); sLen < operation.minStack {
return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack)
} else if sLen > operation.maxStack {
return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack)
}
// If the operation is valid, enforce and write restrictions
if err := in.enforceRestrictions(op, operation, stack); err != nil {
return nil, err
if in.readOnly && in.evm.chainRules.IsS3 {
// If the interpreter is operating in readonly mode, make sure no
// state-modifying operation is performed. The 3rd stack item
// for a call operation is the value. Transferring value from one
// account to the others means the state is modified and should also
// return with an error.
if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) {
return nil, errWriteProtection
}
}
// Static portion of gas
cost = operation.constantGas // For tracing
if !contract.UseGas(operation.constantGas) {
return nil, ErrOutOfGas
}
var memorySize uint64
// calculate the new memory size and expand the memory to fit
// the operation
// Memory check needs to be done prior to evaluating the dynamic gas portion,
// to detect calculation overflows
if operation.memorySize != nil {
memSize, overflow := bigUint64(operation.memorySize(stack))
memSize, overflow := operation.memorySize(stack)
if overflow {
return nil, errGasUintOverflow
}
@ -239,11 +249,16 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
return nil, errGasUintOverflow
}
}
// Dynamic portion of gas
// consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method can get the proper cost
cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
if err != nil || !contract.UseGas(cost) {
return nil, ErrOutOfGas
if operation.dynamicGas != nil {
var dynamicCost uint64
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
cost += dynamicCost // total cost, for debug tracing
if err != nil || !contract.UseGas(dynamicCost) {
return nil, ErrOutOfGas
}
}
if memorySize > 0 {
mem.Resize(memorySize)
@ -255,7 +270,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
// execute the operation
res, err := operation.execute(&pc, in, contract, mem, stack)
res, err = operation.execute(&pc, in, contract, mem, stack)
// verifyPool is a build flag. Pool verification makes sure the integrity
// of the integer pool by comparing values to a default value.
if verifyPool {

File diff suppressed because it is too large Load Diff

@ -51,7 +51,7 @@ type LogConfig struct {
Limit int // maximum length of output, but zero means unlimited
}
// no go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
//go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
// StructLog is emitted to the EVM each cycle and lists information about the current internal state
// prior to the execution of the statement.
@ -98,7 +98,7 @@ func (s *StructLog) ErrorString() string {
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type Tracer interface {
CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
@ -158,7 +158,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
)
l.changedValues[contract.Address()][address] = value
}
// Copy a snapstot of the current memory state to a new buffer
// Copy a snapshot of the current memory state to a new buffer
var mem []byte
if !l.cfg.DisableMemory {
mem = make([]byte, len(memory.Data()))
@ -177,7 +177,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
if !l.cfg.DisableStorage {
storage = l.changedValues[contract.Address()].Copy()
}
// create a new snaptshot of the EVM.
// create a new snapshot of the EVM.
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, env.StateDB.GetRefund(), err}
l.logs = append(l.logs, log)

@ -69,8 +69,8 @@ func (m *Memory) Resize(size uint64) {
}
}
// Get returns offset + size as a new slice
func (m *Memory) Get(offset, size int64) (cpy []byte) {
// GetCopy returns offset + size as a new slice
func (m *Memory) GetCopy(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
}

@ -16,82 +16,98 @@
package vm
import (
"math/big"
"github.com/ethereum/go-ethereum/common/math"
)
func memorySha3(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
func memorySha3(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(1))
}
func memoryCallDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
func memoryCallDataCopy(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(2))
}
func memoryReturnDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
func memoryReturnDataCopy(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(2))
}
func memoryCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
func memoryCodeCopy(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(2))
}
func memoryExtCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(3))
func memoryExtCodeCopy(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(3))
}
func memoryMLoad(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
func memoryMLoad(stack *Stack) (uint64, bool) {
return calcMemSize64WithUint(stack.Back(0), 32)
}
func memoryMStore8(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(1))
func memoryMStore8(stack *Stack) (uint64, bool) {
return calcMemSize64WithUint(stack.Back(0), 1)
}
func memoryMStore(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
func memoryMStore(stack *Stack) (uint64, bool) {
return calcMemSize64WithUint(stack.Back(0), 32)
}
func memoryCreate(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(2))
func memoryCreate(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(2))
}
func memoryCreate2(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(2))
func memoryCreate2(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(2))
}
func memoryCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
return math.BigMax(x, y)
func memoryCall(stack *Stack) (uint64, bool) {
x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
if overflow {
return 0, true
}
y, overflow := calcMemSize64(stack.Back(3), stack.Back(4))
if overflow {
return 0, true
}
if x > y {
return x, false
}
return y, false
}
func memoryDelegateCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
return math.BigMax(x, y)
func memoryDelegateCall(stack *Stack) (uint64, bool) {
x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
if overflow {
return 0, true
}
y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
if overflow {
return 0, true
}
if x > y {
return x, false
}
return y, false
}
func memoryStaticCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
return math.BigMax(x, y)
func memoryStaticCall(stack *Stack) (uint64, bool) {
x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
if overflow {
return 0, true
}
y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
if overflow {
return 0, true
}
if x > y {
return x, false
}
return y, false
}
func memoryReturn(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
func memoryReturn(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(1))
}
func memoryRevert(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
func memoryRevert(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(1))
}
func memoryLog(stack *Stack) *big.Int {
mSize, mStart := stack.Back(1), stack.Back(0)
return calcMemSize(mStart, mSize)
func memoryLog(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(0), stack.Back(1))
}

@ -101,6 +101,8 @@ const (
NUMBER
DIFFICULTY
GASLIMIT
CHAINID = 0x46
SELFBALANCE = 0x47
)
// 0x50 range - 'storage' and execution.
@ -271,12 +273,14 @@ var opCodeToString = map[OpCode]string{
EXTCODEHASH: "EXTCODEHASH",
// 0x40 range - block operations.
BLOCKHASH: "BLOCKHASH",
COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER",
DIFFICULTY: "DIFFICULTY",
GASLIMIT: "GASLIMIT",
BLOCKHASH: "BLOCKHASH",
COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER",
DIFFICULTY: "DIFFICULTY",
GASLIMIT: "GASLIMIT",
CHAINID: "CHAINID",
SELFBALANCE: "SELFBALANCE",
// 0x50 range - 'storage' and execution.
POP: "POP",
@ -428,6 +432,7 @@ var stringToOp = map[string]OpCode{
"CALLDATALOAD": CALLDATALOAD,
"CALLDATASIZE": CALLDATASIZE,
"CALLDATACOPY": CALLDATACOPY,
"CHAINID": CHAINID,
"DELEGATECALL": DELEGATECALL,
"STATICCALL": STATICCALL,
"CODESIZE": CODESIZE,
@ -444,6 +449,7 @@ var stringToOp = map[string]OpCode{
"NUMBER": NUMBER,
"DIFFICULTY": DIFFICULTY,
"GASLIMIT": GASLIMIT,
"SELFBALANCE": SELFBALANCE,
"POP": POP,
"MLOAD": MLOAD,
"MSTORE": MSTORE,

@ -22,8 +22,8 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
@ -101,7 +101,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.DB, error) {
setDefaults(cfg)
if cfg.State == nil {
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
}
var (
address = common.BytesToAddress([]byte("contract"))
@ -131,7 +131,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
setDefaults(cfg)
if cfg.State == nil {
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
}
var (
vmenv = NewEnv(cfg)

@ -21,9 +21,10 @@ import (
"strings"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
@ -95,7 +96,7 @@ func TestExecute(t *testing.T) {
}
func TestCall(t *testing.T) {
state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
state, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
address := common.HexToAddress("0x0a")
state.SetCode(address, []byte{
byte(vm.PUSH1), 10,
@ -151,7 +152,7 @@ func BenchmarkCall(b *testing.B) {
}
func benchmarkEVMCreate(bench *testing.B, code string) {
var (
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver"))
)

@ -74,13 +74,6 @@ func (st *Stack) Back(n int) *big.Int {
return st.data[st.len()-n-1]
}
func (st *Stack) require(n int) error {
if st.len() < n {
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
}
return nil
}
// Print dumps the content of the stack
func (st *Stack) Print() {
fmt.Println("### stack ###")

@ -17,28 +17,26 @@
package vm
import (
"fmt"
"github.com/harmony-one/harmony/internal/params"
"github.com/ethereum/go-ethereum/params"
)
func makeStackFunc(pop, push int) stackValidationFunc {
return func(stack *Stack) error {
if err := stack.require(pop); err != nil {
return err
}
if stack.len()+push-pop > int(params.StackLimit) {
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
}
return nil
}
func minSwapStack(n int) int {
return minStack(n, n)
}
func maxSwapStack(n int) int {
return maxStack(n, n)
}
func makeDupStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, n+1)
func minDupStack(n int) int {
return minStack(n, n+1)
}
func maxDupStack(n int) int {
return maxStack(n, n+1)
}
func makeSwapStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, n)
func maxStack(pop, push int) int {
return int(params.StackLimit) + pop - push
}
func minStack(pops, push int) int {
return pops
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -3,25 +3,31 @@ module github.com/harmony-one/harmony
go 1.14
require (
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/VictoriaMetrics/fastcache v1.5.7 // indirect
github.com/Workiva/go-datastructures v1.0.50
github.com/allegro/bigcache v1.2.1 // indirect
github.com/aristanetworks/goarista v0.0.0-20190607111240-52c2a7864a08 // indirect
github.com/aws/aws-sdk-go v1.30.1
github.com/beorn7/perks v1.0.1 // indirect
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/btcsuite/btcutil v1.0.2
github.com/cespare/cp v1.1.1
github.com/coinbase/rosetta-sdk-go v0.3.4
github.com/coinbase/rosetta-sdk-go v0.4.4
github.com/davecgh/go-spew v1.1.1
github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f // indirect
github.com/deckarep/golang-set v1.7.1
github.com/dlclark/regexp2 v1.2.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.9.18
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa // indirect
github.com/ethereum/go-ethereum v1.9.21
github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a // indirect
github.com/garslo/gogen v0.0.0-20170307003452-d6ebae628c7c // indirect
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
github.com/golang/mock v1.4.0
github.com/golang/protobuf v1.4.2
github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 // indirect
github.com/golangci/golangci-lint v1.22.2
github.com/gorilla/mux v1.7.4
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2 // indirect
github.com/harmony-ek/gencodec v0.0.0-20190215044613-e6740dbdd846
github.com/harmony-one/abool v1.0.1
@ -29,6 +35,7 @@ require (
github.com/harmony-one/taggedrlp v0.1.4
github.com/harmony-one/vdf v0.0.0-20190924175951-620379da8849
github.com/hashicorp/golang-lru v0.5.4
github.com/holiman/uint256 v1.1.1 // indirect
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 // indirect
github.com/ipfs/go-ds-badger v0.2.4
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
@ -45,6 +52,7 @@ require (
github.com/libp2p/go-libp2p-peer v0.2.0 // indirect
github.com/libp2p/go-libp2p-peerstore v0.2.6 // indirect
github.com/libp2p/go-libp2p-pubsub v0.3.3
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/multiformats/go-multiaddr v0.2.2
github.com/multiformats/go-multiaddr-net v0.1.5
github.com/natefinch/lumberjack v2.0.0+incompatible
@ -55,25 +63,28 @@ require (
github.com/prometheus/procfs v0.0.3 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0
github.com/rjeczalik/notify v0.9.2
github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/rs/zerolog v1.18.0
github.com/shirou/gopsutil v2.18.12+incompatible // indirect
github.com/shirou/gopsutil v2.20.5+incompatible // indirect
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.1
github.com/stretchr/testify v1.6.1
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/tools v0.0.0-20200408032209-46bd65c8538f
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/tools v0.0.0-20200904185747-39188db58858
google.golang.org/grpc v1.28.1
google.golang.org/protobuf v1.23.0
google.golang.org/protobuf v1.25.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
gopkg.in/yaml.v2 v2.2.7
gopkg.in/yaml.v2 v2.3.0
)
replace github.com/ethereum/go-ethereum => github.com/ethereum/go-ethereum v1.8.27
replace github.com/ethereum/go-ethereum => github.com/ethereum/go-ethereum v1.9.9

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/core/bloombits"
ethRawDB "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
@ -103,7 +104,7 @@ func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *core.ChainIndexe
db: db,
size: size,
}
table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
table := ethRawDB.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
return core.NewChainIndexer(db, table, backend, size, confirms, bloomThrottling, "bloombits")
}

@ -35,6 +35,7 @@ var (
RedelegationEpoch: big.NewInt(290),
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
IstanbulEpoch: big.NewInt(10000000),
ReceiptLogEpoch: big.NewInt(101),
}
@ -50,6 +51,7 @@ var (
RedelegationEpoch: big.NewInt(36500),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(43800),
ReceiptLogEpoch: big.NewInt(0),
}
@ -66,6 +68,7 @@ var (
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
@ -82,6 +85,7 @@ var (
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
@ -98,6 +102,7 @@ var (
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
@ -113,6 +118,7 @@ var (
RedelegationEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
}
@ -130,6 +136,7 @@ var (
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
}
@ -147,6 +154,7 @@ var (
big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // EIP155Epoch
big.NewInt(0), // S3Epoch
big.NewInt(0), // IstanbulEpoch
big.NewInt(0), // ReceiptLogEpoch
}
@ -206,6 +214,9 @@ type ChainConfig struct {
// S3 epoch is the first epoch containing S3 mainnet and all ethereum update up to Constantinople
S3Epoch *big.Int `json:"s3-epoch,omitempty"`
// Istanbul epoch
IstanbulEpoch *big.Int `json:"istanbul-epoch,omitempty"`
// ReceiptLogEpoch is the first epoch support receiptlog
ReceiptLogEpoch *big.Int `json:"receipt-log-epoch,omitempty"`
}
@ -282,6 +293,11 @@ func (c *ChainConfig) IsS3(epoch *big.Int) bool {
return isForked(c.S3Epoch, epoch)
}
// IsIstanbul returns whether epoch is either equal to the Istanbul fork epoch or greater.
func (c *ChainConfig) IsIstanbul(epoch *big.Int) bool {
return isForked(c.IstanbulEpoch, epoch)
}
// IsReceiptLog returns whether epoch is either equal to the ReceiptLog fork epoch or greater.
func (c *ChainConfig) IsReceiptLog(epoch *big.Int) bool {
return isForked(c.ReceiptLogEpoch, epoch)
@ -316,8 +332,8 @@ func isForked(s, epoch *big.Int) bool {
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainID *big.Int
IsCrossLink, IsEIP155, IsS3, IsReceiptLog bool
ChainID *big.Int
IsCrossLink, IsEIP155, IsS3, IsReceiptLog, IsIstanbul bool
}
// Rules ensures c's ChainID is not nil.
@ -332,5 +348,6 @@ func (c *ChainConfig) Rules(epoch *big.Int) Rules {
IsEIP155: c.IsEIP155(epoch),
IsS3: c.IsS3(epoch),
IsReceiptLog: c.IsReceiptLog(epoch),
IsIstanbul: c.IsIstanbul(epoch),
}
}

@ -1,5 +1,8 @@
package params
import "math/big"
// nolint
const (
// GasLimitBoundDivisor ...
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
@ -64,6 +67,23 @@ const (
// NetSstoreResetClearRefund ...
NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value
// SstoreSentryGasEIP2200 ...
SstoreSentryGasEIP2200 uint64 = 2300 // Minimum gas required to be present for an SSTORE call, not consumed
// SstoreNoopGasEIP2200 ...
SstoreNoopGasEIP2200 uint64 = 800 // Once per SSTORE operation if the value doesn't change.
// SstoreDirtyGasEIP2200 ...
SstoreDirtyGasEIP2200 uint64 = 800 // Once per SSTORE operation if a dirty value is changed.
// SstoreInitGasEIP2200 ...
SstoreInitGasEIP2200 uint64 = 20000 // Once per SSTORE operation from clean zero to non-zero
// SstoreInitRefundEIP2200 ...
SstoreInitRefundEIP2200 uint64 = 19200 // Once per SSTORE operation for resetting to the original zero value
// SstoreCleanGasEIP2200 ...
SstoreCleanGasEIP2200 uint64 = 5000 // Once per SSTORE operation from clean non-zero to something else
// SstoreCleanRefundEIP2200 ...
SstoreCleanRefundEIP2200 uint64 = 4200 // Once per SSTORE operation for resetting to the original non-zero value
// SstoreClearRefundEIP2200 ...
SstoreClearRefundEIP2200 uint64 = 15000 // Once per SSTORE operation for clearing an originally existing storage slot
// JumpdestGas ...
JumpdestGas uint64 = 1 // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
// EpochDuration ...
@ -90,40 +110,72 @@ const (
CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
// Create2Gas ...
Create2Gas uint64 = 32000 // Once per CREATE2 operation
// SuicideRefundGas ...
SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation.
// SelfdestructRefundGas ...
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
// MemoryGas ...
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
// TxDataNonZeroGas ...
TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
// TxDataNonZeroGasEIP2028 ...
TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
// These have been changed during the course of the chain
CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction.
CallGasEIP150 uint64 = 700 // Static portion of gas for CALL-derivates after EIP 150 (Tangerine)
BalanceGasFrontier uint64 = 20 // The cost of a BALANCE operation
BalanceGasEIP150 uint64 = 400 // The cost of a BALANCE operation after Tangerine
BalanceGasEIP1884 uint64 = 700 // The cost of a BALANCE operation after EIP 1884 (part of Istanbul)
ExtcodeSizeGasFrontier uint64 = 20 // Cost of EXTCODESIZE before EIP 150 (Tangerine)
ExtcodeSizeGasEIP150 uint64 = 700 // Cost of EXTCODESIZE after EIP 150 (Tangerine)
SloadGasFrontier uint64 = 50
SloadGasEIP150 uint64 = 200
SloadGasEIP1884 uint64 = 800 // Cost of SLOAD after EIP 1884 (part of Istanbul)
ExtcodeHashGasConstantinople uint64 = 400 // Cost of EXTCODEHASH (introduced in Constantinople)
ExtcodeHashGasEIP1884 uint64 = 700 // Cost of EXTCODEHASH after EIP 1884 (part in Istanbul)
SelfdestructGasEIP150 uint64 = 5000 // Cost of SELFDESTRUCT post EIP 150 (Tangerine)
// EXP has a dynamic portion depending on the size of the exponent
ExpByteFrontier uint64 = 10 // was set to 10 in Frontier
ExpByteEIP158 uint64 = 50 // was raised to 50 during Eip158 (Spurious Dragon)
// Extcodecopy has a dynamic AND a static cost. This represents only the
// static portion of the gas. It was changed during EIP 150 (Tangerine)
ExtcodeCopyBaseFrontier uint64 = 20
ExtcodeCopyBaseEIP150 uint64 = 700
// CreateBySelfdestructGas is used when the refunded account is one that does
// not exist. This logic is similar to call.
// Introduced in Tangerine Whistle (Eip 150)
CreateBySelfdestructGas uint64 = 25000
// MaxCodeSize ...
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
// Precompiled contract gas prices
// EcrecoverGas ...
EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price
// Sha256BaseGas ...
Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation
// Sha256PerWordGas ...
Sha256PerWordGas uint64 = 12 // Per-word price for a SHA256 operation
// Ripemd160BaseGas ...
Ripemd160BaseGas uint64 = 600 // Base price for a RIPEMD160 operation
// Ripemd160PerWordGas ...
Ripemd160PerWordGas uint64 = 120 // Per-word price for a RIPEMD160 operation
// IdentityBaseGas ...
IdentityBaseGas uint64 = 15 // Base price for a data copy operation
// IdentityPerWordGas ...
IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation
// ModExpQuadCoeffDiv ...
ModExpQuadCoeffDiv uint64 = 20 // Divisor for the quadratic particle of the big int modular exponentiation
// Bn256AddGas ...
Bn256AddGas uint64 = 500 // Gas needed for an elliptic curve addition
// Bn256ScalarMulGas ...
Bn256ScalarMulGas uint64 = 40000 // Gas needed for an elliptic curve scalar multiplication
// Bn256PairingBaseGas ...
Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check
// Bn256PairingPerPointGas ...
Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check
EcrecoverGas uint64 = 3000 // Elliptic curve sender recovery gas price
Sha256BaseGas uint64 = 60 // Base price for a SHA256 operation
Sha256PerWordGas uint64 = 12 // Per-word price for a SHA256 operation
Ripemd160BaseGas uint64 = 600 // Base price for a RIPEMD160 operation
Ripemd160PerWordGas uint64 = 120 // Per-word price for a RIPEMD160 operation
IdentityBaseGas uint64 = 15 // Base price for a data copy operation
IdentityPerWordGas uint64 = 3 // Per-work price for a data copy operation
ModExpQuadCoeffDiv uint64 = 20 // Divisor for the quadratic particle of the big int modular exponentiation
Bn256AddGasByzantium uint64 = 500 // Byzantium gas needed for an elliptic curve addition
Bn256AddGasIstanbul uint64 = 150 // Gas needed for an elliptic curve addition
Bn256ScalarMulGasByzantium uint64 = 40000 // Byzantium gas needed for an elliptic curve scalar multiplication
Bn256ScalarMulGasIstanbul uint64 = 6000 // Gas needed for an elliptic curve scalar multiplication
Bn256PairingBaseGasByzantium uint64 = 100000 // Byzantium base price for an elliptic curve pairing check
Bn256PairingBaseGasIstanbul uint64 = 45000 // Base price for an elliptic curve pairing check
Bn256PairingPerPointGasByzantium uint64 = 80000 // Byzantium per-point price for an elliptic curve pairing check
Bn256PairingPerPointGasIstanbul uint64 = 34000 // Per-point price for an elliptic curve pairing check
)
// nolint
var (
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
)

@ -4,6 +4,8 @@ import (
"fmt"
"path"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
)
@ -22,7 +24,7 @@ type LDBFactory struct {
// NewChainDB returns a new LDB for the blockchain for given shard.
func (f *LDBFactory) NewChainDB(shardID uint32) (ethdb.Database, error) {
dir := path.Join(f.RootDir, fmt.Sprintf("harmony_db_%d", shardID))
return ethdb.NewLDBDatabase(dir, 128, 64)
return rawdb.NewLevelDBDatabase(dir, 128, 64, "")
}
// MemDBFactory is a memory-backed blockchain database factory.
@ -30,5 +32,5 @@ type MemDBFactory struct{}
// NewChainDB returns a new memDB for the blockchain for given shard.
func (f *MemDBFactory) NewChainDB(shardID uint32) (ethdb.Database, error) {
return ethdb.NewMemDatabase(), nil
return rawdb.NewMemoryDatabase(), nil
}

@ -228,6 +228,7 @@ func (w *Worker) commitTransaction(
}
w.current.txs = append(w.current.txs, tx)
w.current.receipts = append(w.current.receipts, receipt)
if cx != nil {
w.current.outcxs = append(w.current.outcxs, cx)
}

@ -5,9 +5,10 @@ import (
"math/rand"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/core"
@ -30,7 +31,7 @@ var (
func TestNewWorker(t *testing.T) {
// Setup a new blockchain with genesis block containing test token on test address
var (
database = ethdb.NewMemDatabase()
database = rawdb.NewMemoryDatabase()
gspec = core.Genesis{
Config: chainConfig,
Factory: blockFactory,
@ -41,8 +42,11 @@ func TestNewWorker(t *testing.T) {
genesis := gspec.MustCommit(database)
_ = genesis
chain, _ := core.NewBlockChain(database, nil, gspec.Config, chain2.Engine, vm.Config{}, nil)
chain, err := core.NewBlockChain(database, nil, gspec.Config, chain2.Engine, vm.Config{}, nil)
if err != nil {
t.Error(err)
}
// Create a new worker
worker := New(params.TestChainConfig, chain, chain2.Engine)
@ -54,7 +58,7 @@ func TestNewWorker(t *testing.T) {
func TestCommitTransactions(t *testing.T) {
// Setup a new blockchain with genesis block containing test token on test address
var (
database = ethdb.NewMemDatabase()
database = rawdb.NewMemoryDatabase()
gspec = core.Genesis{
Config: chainConfig,
Factory: blockFactory,

@ -8,10 +8,11 @@ import (
"strings"
"testing"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
blockfactory "github.com/harmony-one/harmony/block/factory"
consensus_sig "github.com/harmony-one/harmony/consensus/signature"
@ -990,7 +991,7 @@ func defaultTestStateDB() *state.DB {
}
func makeTestStateDB() *state.DB {
db := state.NewDatabase(ethdb.NewMemDatabase())
db := state.NewDatabase(rawdb.NewMemoryDatabase())
sdb, err := state.New(common.Hash{}, db)
if err != nil {
panic(err)

@ -108,7 +108,7 @@ type EditValidator struct {
SlotKeyToRemove *bls.SerializedPublicKey `json:"slot-key-to_remove" rlp:"nil"`
SlotKeyToAdd *bls.SerializedPublicKey `json:"slot-key-to_add" rlp:"nil"`
SlotKeyToAddSig *bls.SerializedSignature `json:"slot-key-to-add-sig" rlp:"nil"`
EPOSStatus effective.Eligibility `json:"epos-eligibility-status" rlp:"nil"`
EPOSStatus effective.Eligibility `json:"epos-eligibility-status"`
}
// Type of EditValidator

@ -6,6 +6,8 @@ import (
"log"
"math/big"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@ -37,7 +39,7 @@ var (
blockFactory = blockfactory.ForTest
// Test transactions
pendingTxs []*types.Transaction
database = ethdb.NewMemDatabase()
database = rawdb.NewMemoryDatabase()
gspec = core.Genesis{
Config: chainConfig,
Factory: blockFactory,

@ -6,6 +6,8 @@ import (
"math/rand"
"time"
"github.com/ethereum/go-ethereum/core/rawdb"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
"github.com/harmony-one/harmony/crypto/bls"
@ -15,7 +17,6 @@ import (
common2 "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
@ -104,11 +105,11 @@ func main() {
GasLimit: 1e18,
ShardID: 0,
}
database := ethdb.NewMemDatabase()
database := rawdb.NewMemoryDatabase()
genesis := gspec.MustCommit(database)
_ = genesis
bc, _ := core.NewBlockChain(database, nil, gspec.Config, chain.Engine, vm.Config{}, nil)
statedb, _ := state.New(common2.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
statedb, _ := state.New(common2.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
msg := createValidator()
statedb.AddBalance(msg.ValidatorAddress, new(big.Int).Mul(big.NewInt(5e18), big.NewInt(2000)))
validator, err := core.VerifyAndCreateValidatorFromMsg(

Loading…
Cancel
Save