Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
joanestebanr committed Jul 1, 2024
1 parent 5dcc6eb commit 5ec3939
Show file tree
Hide file tree
Showing 18 changed files with 704 additions and 14 deletions.
26 changes: 25 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ import (
"github.com/0xPolygon/cdk/dataavailability/datacommittee"
"github.com/0xPolygon/cdk/db"
"github.com/0xPolygon/cdk/etherman"
"github.com/0xPolygon/cdk/etherman2"
"github.com/0xPolygon/cdk/log"
"github.com/0xPolygon/cdk/sequencesender"
"github.com/0xPolygon/cdk/sequencesender/etherman2seqsender"
"github.com/0xPolygon/cdk/sequencesender/txbuilder"
"github.com/0xPolygon/cdk/state"
"github.com/0xPolygon/cdk/state/pgstatestorage"
ethtxman "github.com/0xPolygonHermez/zkevm-ethtx-manager/etherman"
Expand Down Expand Up @@ -132,13 +135,34 @@ func createSequenceSender(cfg config.Config) *sequencesender.SequenceSender {
if err != nil {
log.Fatal(err)
}

eth2, err := etherman2.NewEtherman2Builder().
ChainReader(cfg.Etherman.URL).
AuthStore(nil).
Build(context.Background())
if err != nil {
log.Fatal(err)
}
err = eth2.AddOrReplaceAuth(*auth)
if err != nil {
log.Fatal(err)
}
cfg.SequenceSender.SenderAddress = auth.From

da, err := newDataAvailability(cfg, ethman)
if err != nil {
log.Fatal(err)
}

txBuilder := txbuilder.NewTxBuilderSelector(txbuilder.NewSelectorPerForkID())
if cfg.SequenceSender.IsValidiumMode {
eth2c := etherman2seqsender.NewEth2Elderberry(nil)
err := eth2c.LoadContract(cfg.NetworkConfig.L1Config.ZkEVMAddr, ethman.EthClient)
if err != nil {
log.Fatal(err)
}
txBV := txbuilder.NewBuildSequenceBatchesTxValidium(da, eth2c, cfg.SequenceSender.L2Coinbase, auth)
txBuilder.Register("elderberry", txBV)
}
seqSender, err := sequencesender.New(cfg.SequenceSender, ethman, da)
if err != nil {
log.Fatal(err)
Expand Down
115 changes: 115 additions & 0 deletions etherman2/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package etherman2

import (
"context"
"fmt"

"github.com/0xPolygon/cdk/etherman2/internal"
"github.com/ethereum/go-ethereum/ethclient"
)

type etherman2Impl struct {
*internal.Etherman2AuthStore
*internal.Etherman2ChainReader
}

/*
Example of usage:
etherman2builder := etherman2.NewEtherman2Builder().
ChainReader("http://localhost:8545").
AuthStore(nil)
etherman2, err:= etherman2builder.Build(context.Background())
*/

type Etherman2Builder struct {
L1EthClient *ethclient.Client
chainReader struct {
enabled bool
l1url string
}
authStore *struct {
enabled bool
forcedChainID *uint64
}
result etherman2Impl
}

func NewEtherman2Builder() *Etherman2Builder {
return &Etherman2Builder{}
}

func (e *Etherman2Builder) ChainReader(l1url string) *Etherman2Builder {
e.chainReader.enabled = true
e.chainReader.l1url = l1url
return e
}

func (e *Etherman2Builder) AuthStore(forcedChainID *uint64) *Etherman2Builder {
e.authStore.enabled = true
e.authStore.forcedChainID = forcedChainID
return e
}

func (e *Etherman2Builder) Build(ctx context.Context) (*etherman2Impl, error) {
if e.chainReader.enabled {
err := e.newChainReader()
if err != nil {
return nil, err
}
}
if e.authStore.enabled {
err := e.newAuthStore(ctx)
if err != nil {
return nil, err
}
}
return &e.result, nil
}

func (e *Etherman2Builder) newChainReader() error {
if e.chainReader.enabled {
client, err := ethclient.Dial(e.chainReader.l1url)
if err != nil {
return err
}
e.L1EthClient = client
}
if e.chainReader.enabled {
var err error
e.result.Etherman2ChainReader, err = internal.NewEtherman2ChainReader(e.L1EthClient)
if err != nil {
return err
}

return nil
}
return nil
}

func (e *Etherman2Builder) newAuthStore(ctx context.Context) error {
if e.authStore.enabled {
chainID, err := e.getChainID(ctx)
e.result.Etherman2AuthStore, err = internal.NewEtherman2L1Auth(chainID)
if err != nil {
return err
}
}
return nil
}

func (e *Etherman2Builder) getChainID(ctx context.Context) (uint64, error) {
var chainID uint64
if e.authStore.forcedChainID != nil {
chainID = *e.authStore.forcedChainID
return chainID, nil

}
if e.result.Etherman2ChainReader == nil {
return 0, fmt.Errorf("chain reader not initialized, so or force ChainID or build also a chain reader (ChainReader() )")
}
chainID, err := e.result.Etherman2ChainReader.ChainID(ctx)
if err != nil {
return 0, err
}
return chainID, nil
}
52 changes: 52 additions & 0 deletions etherman2/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package etherman2

import (
"errors"
"strings"
)

var (
// ErrGasRequiredExceedsAllowance gas required exceeds the allowance
ErrGasRequiredExceedsAllowance = errors.New("gas required exceeds allowance")
// ErrContentLengthTooLarge content length is too large
ErrContentLengthTooLarge = errors.New("content length too large")
//ErrTimestampMustBeInsideRange Timestamp must be inside range
ErrTimestampMustBeInsideRange = errors.New("timestamp must be inside range")
//ErrInsufficientAllowance insufficient allowance
ErrInsufficientAllowance = errors.New("insufficient allowance")
// ErrBothGasPriceAndMaxFeeGasAreSpecified both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified
ErrBothGasPriceAndMaxFeeGasAreSpecified = errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
// ErrMaxFeeGasAreSpecifiedButLondonNotActive maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet
ErrMaxFeeGasAreSpecifiedButLondonNotActive = errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
// ErrNoSigner no signer to authorize the transaction with
ErrNoSigner = errors.New("no signer to authorize the transaction with")
// ErrMissingTrieNode means that a node is missing on the trie
ErrMissingTrieNode = errors.New("missing trie node")
// ErrNotFound is used when the object is not found
ErrNotFound = errors.New("not found")
// ErrPrivateKeyNotFound used when the provided sender does not have a private key registered to be used
ErrPrivateKeyNotFound = errors.New("can't find sender private key to sign tx")

errorsCache = map[string]error{
ErrGasRequiredExceedsAllowance.Error(): ErrGasRequiredExceedsAllowance,
ErrContentLengthTooLarge.Error(): ErrContentLengthTooLarge,
ErrTimestampMustBeInsideRange.Error(): ErrTimestampMustBeInsideRange,
ErrInsufficientAllowance.Error(): ErrInsufficientAllowance,
ErrBothGasPriceAndMaxFeeGasAreSpecified.Error(): ErrBothGasPriceAndMaxFeeGasAreSpecified,
ErrMaxFeeGasAreSpecifiedButLondonNotActive.Error(): ErrMaxFeeGasAreSpecifiedButLondonNotActive,
ErrNoSigner.Error(): ErrNoSigner,
ErrMissingTrieNode.Error(): ErrMissingTrieNode,
}
)

func TryParseError(err error) (error, bool) {
parsedError, exists := errorsCache[err.Error()]
if !exists {
for errStr, actualErr := range errorsCache {
if strings.Contains(err.Error(), errStr) {
return actualErr, true
}
}
}
return parsedError, exists
}
34 changes: 34 additions & 0 deletions etherman2/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package etherman2

import (
"context"
"crypto/ecdsa"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)

type Etherman2ChainReader interface {
LastL1BlockNumber(ctx context.Context) (uint64, error)
ChainID(ctx context.Context) (uint64, error)
}

type Etherman2AuthStorerRO interface {
GetAuthByAddress(addr common.Address) (bind.TransactOpts, bool)
}

// Etherman2AuthStorerRW is an interface that extends Etherman2AuthStorerRO providing write capabilities
type Etherman2AuthStorerRW interface {
Etherman2AuthStorerRO
LoadAuthFromKeyStore(path, password string) (*bind.TransactOpts, *ecdsa.PrivateKey, error)
AddOrReplaceAuth(auth bind.TransactOpts) error
}

type Etherman2ContractLoader[T any] interface {
LoadContract(address common.Address, backend bind.ContractBackend, funcConstructor func(common.Address, bind.ContractBackend) (T, error)) (T, error)
}

type Etherman2 interface {
Etherman2ChainReader
Etherman2AuthStorerRW
}
85 changes: 85 additions & 0 deletions etherman2/internal/eth2auth_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package internal

import (
"crypto/ecdsa"
"math/big"
"os"
"path/filepath"

"github.com/0xPolygon/cdk/log"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
)

type Etherman2AuthStore struct {
chainID uint64
auth map[common.Address]bind.TransactOpts // empty in case of read-only client
}

func NewEtherman2L1Auth(chainID uint64) (*Etherman2AuthStore, error) {
return &Etherman2AuthStore{
chainID: chainID,
auth: map[common.Address]bind.TransactOpts{},
}, nil
}

// getAuthByAddress tries to get an authorization from the authorizations map
func (etherMan *Etherman2AuthStore) GetAuthByAddress(addr common.Address) (bind.TransactOpts, bool) {
auth, found := etherMan.auth[addr]
return auth, found
}

// LoadAuthFromKeyStore loads an authorization from a key store file
// Store the authorization in the authorizations map and returns it
func (etherMan *Etherman2AuthStore) LoadAuthFromKeyStore(path, password string) (*bind.TransactOpts, *ecdsa.PrivateKey, error) {
auth, pk, err := newAuthFromKeystore(path, password, etherMan.chainID)
if err != nil {
return nil, nil, err
}

log.Infof("loaded authorization for address: %v", auth.From.String())
etherMan.auth[auth.From] = auth
return &auth, pk, nil
}

// AddOrReplaceAuth adds an authorization or replace an existent one to the same account
func (etherMan *Etherman2AuthStore) AddOrReplaceAuth(auth bind.TransactOpts) error {
log.Infof("added or replaced authorization for address: %v", auth.From.String())
etherMan.auth[auth.From] = auth
return nil
}

// newAuthFromKeystore an authorization instance from a keystore file
func newAuthFromKeystore(path, password string, chainID uint64) (bind.TransactOpts, *ecdsa.PrivateKey, error) {
log.Infof("reading key from: %v", path)
key, err := newKeyFromKeystore(path, password)
if err != nil {
return bind.TransactOpts{}, nil, err
}
if key == nil {
return bind.TransactOpts{}, nil, nil
}
auth, err := bind.NewKeyedTransactorWithChainID(key.PrivateKey, new(big.Int).SetUint64(chainID))
if err != nil {
return bind.TransactOpts{}, nil, err
}
return *auth, key.PrivateKey, nil
}

// newKeyFromKeystore creates an instance of a keystore key from a keystore file
func newKeyFromKeystore(path, password string) (*keystore.Key, error) {
if path == "" && password == "" {
return nil, nil
}
keystoreEncrypted, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return nil, err
}
log.Infof("decrypting key from: %v", path)
key, err := keystore.DecryptKey(keystoreEncrypted, password)
if err != nil {
return nil, err
}
return key, nil
}
58 changes: 58 additions & 0 deletions etherman2/internal/eth2chain_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package internal

import (
"context"
"errors"

"github.com/ethereum/go-ethereum"
)

type Etherman2ChainReader struct {
L1EthClient interface {
ethereum.ChainReader
ethereum.ChainIDReader
}
}

/*
func LoadContract[T any](address common.Address, backend bind.ContractBackend, funcConstructor func(common.Address, bind.ContractBackend) (T, error)) (T, error) {
zkevm, err := funcConstructor(address, backend)
if err != nil {
var nilObject T
return nilObject, err
}
return zkevm, nil
}
*/

func NewEtherman2ChainReader(l1client interface{}) (*Etherman2ChainReader, error) {
client, ok := l1client.(interface {
ethereum.ChainReader
ethereum.ChainIDReader
})
if !ok {
return nil, errors.New("l1client does not implement required interfaces")
}
return &Etherman2ChainReader{L1EthClient: client}, nil
}

func (e *Etherman2ChainReader) LastL1BlockNumber(ctx context.Context) (uint64, error) {
if e == nil || e.L1EthClient == nil {
return 0, nil
}
block, err := e.L1EthClient.BlockByNumber(ctx, nil)
if err != nil {
return 0, err
}
return block.NumberU64(), nil
}
func (e *Etherman2ChainReader) ChainID(ctx context.Context) (uint64, error) {
if e == nil || e.L1EthClient == nil {
return 0, nil
}
id, err := e.L1EthClient.ChainID(ctx)
if err != nil {
return 0, err
}
return id.Uint64(), nil
}
Loading

0 comments on commit 5ec3939

Please sign in to comment.