Skip to content

Commit 2a85c1e

Browse files
committed
store contract in erigon
1 parent 94be7c8 commit 2a85c1e

File tree

6 files changed

+706
-84
lines changed

6 files changed

+706
-84
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package evm
2+
3+
import (
4+
"github.com/iotexproject/go-pkgs/hash"
5+
erigonstate "github.com/ledgerwatch/erigon/core/state"
6+
"github.com/pkg/errors"
7+
8+
"github.com/iotexproject/iotex-core/v2/action/protocol"
9+
"github.com/iotexproject/iotex-core/v2/db/trie"
10+
"github.com/iotexproject/iotex-core/v2/state"
11+
)
12+
13+
type contractReader interface {
14+
GetCommittedState(hash.Hash256) ([]byte, error)
15+
GetState(hash.Hash256) ([]byte, error)
16+
SetState(hash.Hash256, []byte) error
17+
GetCode() ([]byte, error)
18+
SelfState() *state.Account
19+
}
20+
21+
type contractAdapter struct {
22+
contractReader
23+
trie *contract
24+
erigon *contractErigon
25+
}
26+
27+
func newContractAdapter(addr hash.Hash160, account *state.Account, sm protocol.StateManager, intra *erigonstate.IntraBlockState, enableAsync bool) (Contract, error) {
28+
v1, err := newContract(addr, account, sm, enableAsync)
29+
if err != nil {
30+
return nil, errors.Wrap(err, "failed to create contract")
31+
}
32+
v2, err := newContractErigon(addr, account, intra)
33+
if err != nil {
34+
return nil, errors.Wrap(err, "failed to create contractV2")
35+
}
36+
c := &contractAdapter{
37+
contractReader: v1,
38+
trie: v1.(*contract),
39+
erigon: v2.(*contractErigon),
40+
}
41+
return c, nil
42+
}
43+
44+
func (c *contractAdapter) SetState(key hash.Hash256, value []byte) error {
45+
if err := c.trie.SetState(key, value); err != nil {
46+
return err
47+
}
48+
return c.erigon.SetState(key, value)
49+
}
50+
51+
func (c *contractAdapter) SetCode(hash hash.Hash256, code []byte) {
52+
c.trie.SetCode(hash, code)
53+
c.erigon.SetCode(hash, code)
54+
}
55+
56+
func (c *contractAdapter) Commit() error {
57+
if err := c.trie.Commit(); err != nil {
58+
return err
59+
}
60+
return c.erigon.Commit()
61+
}
62+
63+
func (c *contractAdapter) LoadRoot() error {
64+
if err := c.trie.LoadRoot(); err != nil {
65+
return err
66+
}
67+
return c.erigon.LoadRoot()
68+
}
69+
70+
// Iterator is only for debug
71+
func (c *contractAdapter) Iterator() (trie.Iterator, error) {
72+
return nil, errors.New("not supported")
73+
}
74+
75+
func (c *contractAdapter) Snapshot() Contract {
76+
v1 := c.trie.Snapshot().(*contract)
77+
v2 := c.erigon.Snapshot().(*contractErigon)
78+
return &contractAdapter{
79+
contractReader: v1,
80+
trie: v1,
81+
erigon: v2,
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package evm
2+
3+
import (
4+
"math/big"
5+
6+
"github.com/holiman/uint256"
7+
"github.com/iotexproject/go-pkgs/hash"
8+
libcommon "github.com/ledgerwatch/erigon-lib/common"
9+
erigonstate "github.com/ledgerwatch/erigon/core/state"
10+
"github.com/pkg/errors"
11+
12+
"github.com/iotexproject/iotex-core/v2/db/trie"
13+
"github.com/iotexproject/iotex-core/v2/pkg/log"
14+
"github.com/iotexproject/iotex-core/v2/state"
15+
)
16+
17+
type contractErigon struct {
18+
*state.Account
19+
intra *erigonstate.IntraBlockState
20+
addr hash.Hash160
21+
}
22+
23+
func newContractErigon(addr hash.Hash160, account *state.Account, intra *erigonstate.IntraBlockState) (Contract, error) {
24+
c := &contractErigon{
25+
Account: account,
26+
intra: intra,
27+
addr: addr,
28+
}
29+
return c, nil
30+
}
31+
32+
func (c *contractErigon) GetCommittedState(key hash.Hash256) ([]byte, error) {
33+
k := libcommon.Hash(key)
34+
v := uint256.NewInt(0)
35+
c.intra.GetCommittedState(libcommon.Address(c.addr), &k, v)
36+
return v.Bytes(), nil
37+
}
38+
39+
func (c *contractErigon) GetState(key hash.Hash256) ([]byte, error) {
40+
k := libcommon.Hash(key)
41+
v := uint256.NewInt(0)
42+
c.intra.GetState(libcommon.Address(c.addr), &k, v)
43+
return v.Bytes(), nil
44+
}
45+
46+
func (c *contractErigon) SetState(key hash.Hash256, value []byte) error {
47+
k := libcommon.Hash(key)
48+
c.intra.SetState(libcommon.Address(c.addr), &k, *uint256.MustFromBig(big.NewInt(0).SetBytes(value)))
49+
return nil
50+
}
51+
52+
func (c *contractErigon) GetCode() ([]byte, error) {
53+
return c.intra.GetCode(libcommon.Address(c.addr)), nil
54+
}
55+
56+
func (c *contractErigon) SetCode(hash hash.Hash256, code []byte) {
57+
c.intra.SetCode(libcommon.Address(c.addr), code)
58+
eh := c.intra.GetCodeHash(libcommon.Address(c.addr))
59+
log.L().Debug("SetCode", log.Hex("erigonhash", eh[:]), log.Hex("iotexhash", hash[:]))
60+
}
61+
62+
func (c *contractErigon) SelfState() *state.Account {
63+
acc := &state.Account{}
64+
acc.SetPendingNonce(c.intra.GetNonce(libcommon.Address(c.addr)))
65+
acc.AddBalance(c.intra.GetBalance(libcommon.Address(c.addr)).ToBig())
66+
codeHash := c.intra.GetCodeHash(libcommon.Address(c.addr))
67+
acc.CodeHash = codeHash[:]
68+
return acc
69+
}
70+
71+
func (c *contractErigon) Commit() error {
72+
return nil
73+
}
74+
75+
func (c *contractErigon) LoadRoot() error {
76+
return nil
77+
}
78+
79+
// Iterator is only for debug
80+
func (c *contractErigon) Iterator() (trie.Iterator, error) {
81+
return nil, errors.New("not supported")
82+
}
83+
84+
func (c *contractErigon) Snapshot() Contract {
85+
return &contractErigon{
86+
Account: c.Account.Clone(),
87+
intra: c.intra,
88+
}
89+
}

action/protocol/execution/evm/evm.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/ethereum/go-ethereum/crypto"
1919
"github.com/ethereum/go-ethereum/params"
2020
"github.com/holiman/uint256"
21+
erigonstate "github.com/ledgerwatch/erigon/core/state"
2122
"github.com/pkg/errors"
2223
"go.uber.org/zap"
2324
"google.golang.org/protobuf/proto"
@@ -245,7 +246,7 @@ func ExecuteContract(
245246
) ([]byte, *action.Receipt, error) {
246247
ctx, span := tracer.NewSpan(ctx, "evm.ExecuteContract")
247248
defer span.End()
248-
249+
var stateDB stateDB
249250
stateDB, err := prepareStateDB(ctx, sm)
250251
if err != nil {
251252
return nil, nil, err
@@ -254,6 +255,28 @@ func ExecuteContract(
254255
if err != nil {
255256
return nil, nil, err
256257
}
258+
if erigonsm, ok := sm.(interface {
259+
Erigon() (erigonstate.StateWriter, *erigonstate.IntraBlockState, bool)
260+
}); ok {
261+
if sw, in, dryrun := erigonsm.Erigon(); sw != nil && in != nil {
262+
rules := ps.chainConfig.Rules(ps.context.BlockNumber, ps.genesis.IsSumatra(uint64(ps.context.BlockNumber.Int64())), ps.context.Time)
263+
if dryrun {
264+
stateDB = NewErigonStateDBAdapterDryrun(
265+
stateDB.(*StateDBAdapter),
266+
sw,
267+
in,
268+
NewErigonRules(&rules),
269+
)
270+
} else {
271+
stateDB = NewErigonStateDBAdapter(
272+
stateDB.(*StateDBAdapter),
273+
sw,
274+
in,
275+
NewErigonRules(&rules),
276+
)
277+
}
278+
}
279+
}
257280
retval, depositGas, remainingGas, contractAddress, statusCode, err := executeInEVM(ctx, ps, stateDB)
258281
if err != nil {
259282
return nil, nil, err

0 commit comments

Comments
 (0)