Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[draft] contract historical storage by Erigon #4536

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,7 @@ newxctl:
.PHONY: iomigrater
iomigrater:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/$(BUILD_TARGET_IOMIGRATER) -v ./tools/iomigrater

.PHONY: dbwatcher
dbwatcher:
$(GOBUILD) -ldflags "$(PackageFlags)" -o ./bin/dbwatcher -v ./tools/dbwatcher
11 changes: 11 additions & 0 deletions action/protocol/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type (

vmConfigContextKey struct{}

erigonContextKey struct{}

// TipInfo contains the tip block information
TipInfo struct {
Height uint64
Expand Down Expand Up @@ -398,3 +400,12 @@ func GetVMConfigCtx(ctx context.Context) (vm.Config, bool) {
cfg, ok := ctx.Value(vmConfigContextKey{}).(vm.Config)
return cfg, ok
}

func WithErigonCtx(ctx context.Context) context.Context {
return context.WithValue(ctx, erigonContextKey{}, struct{}{})
}

func GetErigonCtx(ctx context.Context) (any, bool) {
v := ctx.Value(erigonContextKey{})
return v, v != nil
}
95 changes: 95 additions & 0 deletions action/protocol/execution/evm/contractv2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package evm

import (
"math/big"

"github.com/holiman/uint256"
"github.com/iotexproject/go-pkgs/hash"
libcommon "github.com/ledgerwatch/erigon-lib/common"
erigonstate "github.com/ledgerwatch/erigon/core/state"
"github.com/pkg/errors"

"github.com/iotexproject/iotex-core/v2/action/protocol"
"github.com/iotexproject/iotex-core/v2/db/trie"
"github.com/iotexproject/iotex-core/v2/pkg/log"
"github.com/iotexproject/iotex-core/v2/state"
)

type contractV2 struct {
*state.Account
sm protocol.StateReader
intra *erigonstate.IntraBlockState
addr hash.Hash160
}

func newContractV2(addr hash.Hash160, account *state.Account, sm protocol.StateReader, intra *erigonstate.IntraBlockState) (Contract, error) {
c := &contractV2{
Account: account,
sm: sm,
intra: intra,
addr: addr,
}
return c, nil
}

func (c *contractV2) GetCommittedState(key hash.Hash256) ([]byte, error) {
k := libcommon.Hash(key)
v := uint256.NewInt(0)
// Fix(erigon): return err if not exist
c.intra.GetCommittedState(libcommon.Address(c.addr), &k, v)
return v.Bytes(), nil
}

func (c *contractV2) GetState(key hash.Hash256) ([]byte, error) {
k := libcommon.Hash(key)
v := uint256.NewInt(0)
// Fix(erigon): return err if not exist
c.intra.GetState(libcommon.Address(c.addr), &k, v)
return v.Bytes(), nil
}

func (c *contractV2) SetState(key hash.Hash256, value []byte) error {
k := libcommon.Hash(key)
c.intra.SetState(libcommon.Address(c.addr), &k, *uint256.MustFromBig(big.NewInt(0).SetBytes(value)))
return nil
}

func (c *contractV2) GetCode() ([]byte, error) {
return c.intra.GetCode(libcommon.Address(c.addr)), nil
}

func (c *contractV2) SetCode(hash hash.Hash256, code []byte) {
c.intra.SetCode(libcommon.Address(c.addr), code)
eh := c.intra.GetCodeHash(libcommon.Address(c.addr))
log.L().Debug("SetCode", log.Hex("erigonhash", eh[:]), log.Hex("iotexhash", hash[:]))
}

func (c *contractV2) SelfState() *state.Account {
acc := &state.Account{}
acc.SetPendingNonce(c.intra.GetNonce(libcommon.Address(c.addr)))
acc.AddBalance(c.intra.GetBalance(libcommon.Address(c.addr)).ToBig())
codeHash := c.intra.GetCodeHash(libcommon.Address(c.addr))
acc.CodeHash = codeHash[:]
return acc
}

func (c *contractV2) Commit() error {
return nil
}

func (c *contractV2) LoadRoot() error {
return nil
}

// Iterator is only for debug
func (c *contractV2) Iterator() (trie.Iterator, error) {
return nil, errors.New("not supported")
}

func (c *contractV2) Snapshot() Contract {
return &contractV2{
Account: c.Account.Clone(),
sm: c.sm,
intra: c.intra,
}
}
83 changes: 83 additions & 0 deletions action/protocol/execution/evm/contractv3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package evm

import (
"github.com/iotexproject/go-pkgs/hash"
erigonstate "github.com/ledgerwatch/erigon/core/state"
"github.com/pkg/errors"

"github.com/iotexproject/iotex-core/v2/action/protocol"
"github.com/iotexproject/iotex-core/v2/db/trie"
"github.com/iotexproject/iotex-core/v2/state"
)

type contractReader interface {
GetCommittedState(hash.Hash256) ([]byte, error)
GetState(hash.Hash256) ([]byte, error)
SetState(hash.Hash256, []byte) error
GetCode() ([]byte, error)
SelfState() *state.Account
}

type contractV3 struct {
contractReader
v1 *contract
v2 *contractV2
}

func newContractV3(addr hash.Hash160, account *state.Account, sm protocol.StateManager, intra *erigonstate.IntraBlockState, enableAsync bool) (Contract, error) {
v1, err := newContract(addr, account, sm, enableAsync)
if err != nil {
return nil, errors.Wrap(err, "failed to create contract")
}
v2, err := newContractV2(addr, account, sm, intra)
if err != nil {
return nil, errors.Wrap(err, "failed to create contractV2")
}
c := &contractV3{
contractReader: v1,
v1: v1.(*contract),
v2: v2.(*contractV2),
}
return c, nil
}

func (c *contractV3) SetState(key hash.Hash256, value []byte) error {
if err := c.v1.SetState(key, value); err != nil {
return err
}
return c.v2.SetState(key, value)
}

func (c *contractV3) SetCode(hash hash.Hash256, code []byte) {
c.v1.SetCode(hash, code)
c.v2.SetCode(hash, code)
}

func (c *contractV3) Commit() error {
if err := c.v1.Commit(); err != nil {
return err
}
return c.v2.Commit()
}

func (c *contractV3) LoadRoot() error {
if err := c.v1.LoadRoot(); err != nil {
return err
}
return c.v2.LoadRoot()
}

// Iterator is only for debug
func (c *contractV3) Iterator() (trie.Iterator, error) {
return nil, errors.New("not supported")
}

func (c *contractV3) Snapshot() Contract {
v1 := c.v1.Snapshot().(*contract)
v2 := c.v2.Snapshot().(*contractV2)
return &contractV3{
contractReader: v1,
v1: v1,
v2: v2,
}
}
Loading