diff --git a/go.mod b/go.mod index 9987c10d67..a82266e6a3 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,13 @@ replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220224 require ( github.com/allegro/bigcache/v3 v3.1.0 github.com/andybalholm/brotli v1.0.5 + github.com/dgraph-io/ristretto v0.1.1 github.com/docker/docker v1.6.2 github.com/docker/go-connections v0.4.0 github.com/edgelesssys/ego v1.1.0 - github.com/eko/gocache/lib/v4 v4.1.2 - github.com/eko/gocache/store/bigcache/v4 v4.1.2 + github.com/eko/gocache/lib/v4 v4.1.5 + github.com/eko/gocache/store/bigcache/v4 v4.2.1 + github.com/eko/gocache/store/ristretto/v4 v4.2.1 github.com/ethereum/go-ethereum v1.12.2 github.com/gin-contrib/cors v1.4.0 github.com/gin-gonic/gin v1.9.1 @@ -65,6 +67,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect github.com/ethereum/c-kzg-4844 v0.3.1 // indirect github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -82,6 +85,7 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.3.0 // indirect + github.com/golang/glog v1.0.0 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect diff --git a/go.sum b/go.sum index a867591d1b..1930bf71df 100644 --- a/go.sum +++ b/go.sum @@ -129,7 +129,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -140,6 +143,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -148,10 +152,12 @@ github.com/edgelesssys/ego v1.1.0 h1:UcDiGGJ8PF8YStlticxi2hMgPqRTtP42FzaGaAxm9Ys github.com/edgelesssys/ego v1.1.0/go.mod h1:ex4cDvgi0l6wxDm5xBaQzJqi547FMPDsxv+3ERLJfLI= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/eko/gocache/lib/v4 v4.1.2 h1:cX54GhJJsfc5jvCEaPW8595h9Pq6bbNfkv0o/669Tw4= -github.com/eko/gocache/lib/v4 v4.1.2/go.mod h1:FqyrANKct257VFHVVs11m6V2syGobOmHycQCyRSMwu0= -github.com/eko/gocache/store/bigcache/v4 v4.1.2 h1:8uMDpgxTG7BvyLHBFqL3Ao809bVrXfrWqo7v6ALiwTw= -github.com/eko/gocache/store/bigcache/v4 v4.1.2/go.mod h1:Lut5Sk/yI835w02tmwx4ecezYQo445L5sdICsk1zgho= +github.com/eko/gocache/lib/v4 v4.1.5 h1:CeMQmdIzwBKKLRjk3FCDXzNFsQTyqJ01JLI7Ib0C9r8= +github.com/eko/gocache/lib/v4 v4.1.5/go.mod h1:XaNfCwW8KYW1bRZ/KoHA1TugnnkMz0/gT51NDIu7LSY= +github.com/eko/gocache/store/bigcache/v4 v4.2.1 h1:xf9R5HZqmrfT4+NzlJPQJQUWftfWW06FHbjz4IEjE08= +github.com/eko/gocache/store/bigcache/v4 v4.2.1/go.mod h1:Q9+hxUE+XUVGSRGP1tqW8sPHcZ50PfyBVh9VKh0OjrA= +github.com/eko/gocache/store/ristretto/v4 v4.2.1 h1:xB5E1LP1gh8yUV1G3KVRSL4T0OTnxp4OixuTljn2848= +github.com/eko/gocache/store/ristretto/v4 v4.2.1/go.mod h1:KyshDyWQqfSVrg2rH06fFQZTj6vG2fxlY7oAW9oxNHY= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -245,6 +251,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -799,6 +807,7 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/go/common/cache_util.go b/go/common/cache_util.go new file mode 100644 index 0000000000..dafe7d2f8b --- /dev/null +++ b/go/common/cache_util.go @@ -0,0 +1,33 @@ +package common + +import ( + "context" + + "github.com/eko/gocache/lib/v4/cache" + gethlog "github.com/ethereum/go-ethereum/log" + "github.com/ten-protocol/go-ten/go/common/log" +) + +// GetCachedValue - returns the cached value for the provided key. If the key is not found, then invoke the 'onFailed' function +// which returns the value, and cache it +func GetCachedValue[V any](cache *cache.Cache[V], logger gethlog.Logger, key any, onFailed func(any) (V, error)) (V, error) { + value, err := cache.Get(context.Background(), key) + if err != nil { + // todo metrics for cache misses + b, err := onFailed(key) + if err != nil { + return b, err + } + CacheValue(cache, logger, key, b) + return b, err + } + + return value, err +} + +func CacheValue[V any](cache *cache.Cache[V], logger gethlog.Logger, key any, v V) { + err := cache.Set(context.Background(), key, v) + if err != nil { + logger.Error("Could not store value in cache", log.ErrKey, err) + } +} diff --git a/go/common/gethencoding/geth_encoding.go b/go/common/gethencoding/geth_encoding.go index 14bf4c91ad..0391725fa7 100644 --- a/go/common/gethencoding/geth_encoding.go +++ b/go/common/gethencoding/geth_encoding.go @@ -5,9 +5,19 @@ import ( "fmt" "math/big" "strings" + "sync/atomic" + "time" + "unsafe" + + "github.com/dgraph-io/ristretto" + "github.com/eko/gocache/lib/v4/cache" + ristretto_store "github.com/eko/gocache/store/ristretto/v4" + + gethlog "github.com/ethereum/go-ethereum/log" + "github.com/ten-protocol/go-ten/go/common/log" + "github.com/ten-protocol/go-ten/go/enclave/storage" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/trie" "github.com/ten-protocol/go-ten/go/common" "github.com/ten-protocol/go-ten/go/enclave/core" "github.com/ten-protocol/go-ten/go/enclave/crypto" @@ -33,6 +43,39 @@ const ( callFieldMaxPriorityFeePerGas = "maxpriorityfeepergas" ) +// EncodingService handles conversion to Geth data structures +type EncodingService interface { + CreateEthHeaderForBatch(h *common.BatchHeader) (*types.Header, error) + CreateEthBlockFromBatch(b *core.Batch) (*types.Block, error) +} + +type gethEncodingServiceImpl struct { + // conversion is expensive. Cache the converted headers. The key is the hash of the batch. + gethHeaderCache *cache.Cache[*types.Header] + + storage storage.Storage + logger gethlog.Logger +} + +func NewGethEncodingService(storage storage.Storage, logger gethlog.Logger) EncodingService { + // todo (tudor) figure out the best values + ristrettoCache, err := ristretto.NewCache(&ristretto.Config{ + NumCounters: 1000, // number of keys to track frequency of. + MaxCost: 1 << 28, // maximum cost of cache (256MB). + BufferItems: 64, // number of keys per Get buffer. Todo - what is this + }) + if err != nil { + panic(err) + } + ristrettoStore := ristretto_store.NewRistretto(ristrettoCache) + + return &gethEncodingServiceImpl{ + gethHeaderCache: cache.New[*types.Header](ristrettoStore), + storage: storage, + logger: logger, + } +} + // ExtractEthCallMapString extracts the eth_call gethapi.TransactionArgs from an interface{} // it ensures that : // - All types are string @@ -226,41 +269,94 @@ func ExtractEthCall(param interface{}) (*gethapi.TransactionArgs, error) { return callMsg, nil } -// CreateEthHeaderForBatch - the EVM requires an Ethereum "block" header. -// In this function we are creating one from the Batch Header -func CreateEthHeaderForBatch(h *common.BatchHeader, secret []byte) (*types.Header, error) { - // deterministically calculate private randomness that will be exposed to the evm - randomness := crypto.CalculateRootBatchEntropy(secret, h.Number) +// CreateEthHeaderForBatch - the EVM requires an Ethereum header. +// We convert the Batch headers to Ethereum headers to be able to use the Geth EVM. +// Special care must be taken to maintain a valid chain of these converted headers. +func (enc *gethEncodingServiceImpl) CreateEthHeaderForBatch(h *common.BatchHeader) (*types.Header, error) { + // wrap in a caching layer + return common.GetCachedValue(enc.gethHeaderCache, enc.logger, h.Hash(), func(a any) (*types.Header, error) { + // deterministically calculate the private randomness that will be exposed to the EVM + secret, err := enc.storage.FetchSecret() + if err != nil { + enc.logger.Crit("Could not fetch shared secret. Exiting.", log.ErrKey, err) + } + perBatchRandomness := crypto.CalculateRootBatchEntropy(secret[:], h.Number) - baseFee := uint64(0) - if h.BaseFee != nil { - baseFee = h.BaseFee.Uint64() - } + // calculate the converted hash of the parent, for a correct converted chain + // default to the genesis + convertedParentHash := common.GethGenesisParentHash + + if h.SequencerOrderNo.Uint64() > common.L2GenesisSeqNo { + convertedParentHash, err = enc.storage.FetchConvertedHash(h.ParentHash) + if err != nil { + enc.logger.Error("Cannot find the converted value for the parent of", log.BatchSeqNoKey, h.SequencerOrderNo) + return nil, err + } + } - return &types.Header{ - ParentHash: h.ParentHash, - Root: h.Root, - TxHash: h.TxHash, - ReceiptHash: h.ReceiptHash, - Difficulty: big.NewInt(0), - Number: h.Number, - GasLimit: h.GasLimit, - GasUsed: h.GasUsed, - BaseFee: big.NewInt(0).SetUint64(baseFee), - Coinbase: h.Coinbase, - Time: h.Time, - MixDigest: randomness, - Nonce: types.BlockNonce{}, - }, nil + baseFee := uint64(0) + if h.BaseFee != nil { + baseFee = h.BaseFee.Uint64() + } + + gethHeader := types.Header{ + ParentHash: convertedParentHash, + UncleHash: gethcommon.Hash{}, + Root: h.Root, + TxHash: h.TxHash, + ReceiptHash: h.ReceiptHash, + Difficulty: big.NewInt(0), + Number: h.Number, + GasLimit: h.GasLimit, + GasUsed: h.GasUsed, + BaseFee: big.NewInt(0).SetUint64(baseFee), + Coinbase: h.Coinbase, + Time: h.Time, + MixDigest: perBatchRandomness, + Nonce: types.BlockNonce{}, + Extra: h.SequencerOrderNo.Bytes(), + WithdrawalsHash: nil, + BlobGasUsed: nil, + ExcessBlobGas: nil, + Bloom: types.Bloom{}, + } + return &gethHeader, nil + }) } -func CreateEthBlockFromBatch(b *core.Batch) (*types.Block, error) { - blockHeader, err := CreateEthHeaderForBatch(b.Header, nil) +// The Geth "Block" type doesn't expose the header directly. +// This type is required for adjusting the header. +type localBlock struct { + header *types.Header + uncles []*types.Header + transactions types.Transactions + withdrawals types.Withdrawals + + // caches + hash atomic.Value + size atomic.Value + + // These fields are used by package eth to track + // inter-peer block relay. + ReceivedAt time.Time + ReceivedFrom interface{} +} + +func (enc *gethEncodingServiceImpl) CreateEthBlockFromBatch(b *core.Batch) (*types.Block, error) { + blockHeader, err := enc.CreateEthHeaderForBatch(b.Header) if err != nil { return nil, fmt.Errorf("unable to create eth block from batch - %w", err) } - return types.NewBlock(blockHeader, b.Transactions, nil, nil, trie.NewStackTrie(nil)), nil + // adjust the header of the returned block to make sure the hashes align + lb := localBlock{ + header: blockHeader, + uncles: nil, + transactions: b.Transactions, + withdrawals: nil, + } + // cast the correct local structure to the standard geth block. + return (*types.Block)(unsafe.Pointer(&lb)), nil } // DecodeParamBytes decodes the parameters byte array into a slice of interfaces diff --git a/go/common/types.go b/go/common/types.go index d3afa6def0..0f21c6161b 100644 --- a/go/common/types.go +++ b/go/common/types.go @@ -80,6 +80,8 @@ const ( HeightCommittedBlocks = 15 ) +var GethGenesisParentHash = common.Hash{} + // SystemError is the interface for the internal errors generated in the Enclave and consumed by the Host type SystemError interface { Error() string diff --git a/go/enclave/components/batch_executor.go b/go/enclave/components/batch_executor.go index ec38798e44..80d641c012 100644 --- a/go/enclave/components/batch_executor.go +++ b/go/enclave/components/batch_executor.go @@ -8,6 +8,8 @@ import ( "sort" "sync" + "github.com/ten-protocol/go-ten/go/common/gethencoding" + "github.com/ten-protocol/go-ten/go/enclave/gas" "github.com/ten-protocol/go-ten/go/enclave/storage" @@ -34,6 +36,7 @@ var ErrNoTransactionsToProcess = fmt.Errorf("no transactions to process") // batchExecutor - the component responsible for executing batches type batchExecutor struct { storage storage.Storage + gethEncodingService gethencoding.EncodingService crossChainProcessors *crosschain.Processors genesis *genesis.Genesis logger gethlog.Logger @@ -48,6 +51,7 @@ type batchExecutor struct { func NewBatchExecutor( storage storage.Storage, + gethEncodingService gethencoding.EncodingService, cc *crosschain.Processors, genesis *genesis.Genesis, gasOracle gas.Oracle, @@ -57,6 +61,7 @@ func NewBatchExecutor( ) BatchExecutor { return &batchExecutor{ storage: storage, + gethEncodingService: gethEncodingService, crossChainProcessors: cc, genesis: genesis, chainConfig: chainConfig, @@ -417,6 +422,7 @@ func (executor *batchExecutor) processTransactions( stateDB, batch.Header, executor.storage, + executor.gethEncodingService, cc, tCount, noBaseFee, diff --git a/go/enclave/components/rollup_compression.go b/go/enclave/components/rollup_compression.go index f8801f70f4..6769b728d8 100644 --- a/go/enclave/components/rollup_compression.go +++ b/go/enclave/components/rollup_compression.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" + "github.com/ten-protocol/go-ten/go/common/gethencoding" + "golang.org/x/exp/slices" "github.com/ethereum/go-ethereum/params" @@ -49,6 +51,7 @@ type RollupCompression struct { dataCompressionService compression.DataCompressionService batchRegistry BatchRegistry batchExecutor BatchExecutor + gethEncodingService gethencoding.EncodingService storage storage.Storage chainConfig *params.ChainConfig logger gethlog.Logger @@ -60,6 +63,7 @@ func NewRollupCompression( dataEncryptionService crypto.DataEncryptionService, dataCompressionService compression.DataCompressionService, storage storage.Storage, + gethEncodingService gethencoding.EncodingService, chainConfig *params.ChainConfig, logger gethlog.Logger, ) *RollupCompression { @@ -69,6 +73,7 @@ func NewRollupCompression( dataEncryptionService: dataEncryptionService, dataCompressionService: dataCompressionService, storage: storage, + gethEncodingService: gethEncodingService, chainConfig: chainConfig, logger: logger, } @@ -421,10 +426,16 @@ func (rc *RollupCompression) executeAndSaveIncompleteBatches(calldataRollupHeade switch { // this batch was re-orged case incompleteBatch.header != nil: - err := rc.storage.StoreBatch(&core.Batch{ + + convertedHeader, err := rc.gethEncodingService.CreateEthHeaderForBatch(incompleteBatch.header) + if err != nil { + return err + } + + err = rc.storage.StoreBatch(&core.Batch{ Header: incompleteBatch.header, Transactions: incompleteBatch.transactions, - }) + }, convertedHeader.Hash()) if err != nil { return err } @@ -446,7 +457,12 @@ func (rc *RollupCompression) executeAndSaveIncompleteBatches(calldataRollupHeade rc.logger.Crit("Rollup decompression failure. The check hashes don't match") }*/ - err = rc.storage.StoreBatch(genBatch) + convertedHeader, err := rc.gethEncodingService.CreateEthHeaderForBatch(genBatch.Header) + if err != nil { + return err + } + + err = rc.storage.StoreBatch(genBatch, convertedHeader.Hash()) if err != nil { return err } @@ -483,7 +499,12 @@ func (rc *RollupCompression) executeAndSaveIncompleteBatches(calldataRollupHeade return fmt.Errorf("cannot commit stateDB for incoming valid batch seq=%d. Cause: %w", incompleteBatch.seqNo, err) } - err = rc.storage.StoreBatch(computedBatch.Batch) + convertedHeader, err := rc.gethEncodingService.CreateEthHeaderForBatch(computedBatch.Batch.Header) + if err != nil { + return err + } + + err = rc.storage.StoreBatch(computedBatch.Batch, convertedHeader.Hash()) if err != nil { return err } diff --git a/go/enclave/crosschain/block_message_extractor.go b/go/enclave/crosschain/block_message_extractor.go index 8742c894c6..ed9fa1afa3 100644 --- a/go/enclave/crosschain/block_message_extractor.go +++ b/go/enclave/crosschain/block_message_extractor.go @@ -61,7 +61,7 @@ func (m *blockMessageExtractor) StoreCrossChainValueTransfers(block *common.L1Bl return nil } - m.logger.Trace(fmt.Sprintf("Storing %d value transfers for block", len(transfers)), log.BlockHashKey, block.Hash()) + m.logger.Trace("Storing value transfers for block", "nr", len(transfers), log.BlockHashKey, block.Hash()) err = m.storage.StoreValueTransfers(block.Hash(), transfers) if err != nil { m.logger.Crit("Unable to store the transfers", log.ErrKey, err) @@ -82,7 +82,7 @@ func (m *blockMessageExtractor) StoreCrossChainMessages(block *common.L1Block, r return nil } - lazilyLogReceiptChecksum(fmt.Sprintf("Processing block: %s receipts: %d", block.Hash(), len(receipts)), receipts, m.logger) + lazilyLogReceiptChecksum(block, receipts, m.logger) messages, err := m.getCrossChainMessages(block, receipts) if err != nil { m.logger.Error("Converting receipts to messages failed.", log.ErrKey, err) diff --git a/go/enclave/crosschain/common.go b/go/enclave/crosschain/common.go index f9a91782e8..c18bec19e5 100644 --- a/go/enclave/crosschain/common.go +++ b/go/enclave/crosschain/common.go @@ -5,6 +5,8 @@ import ( "errors" "strings" + "github.com/ten-protocol/go-ten/go/common/log" + "github.com/ethereum/go-ethereum/accounts/abi" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -23,8 +25,8 @@ var ( ValueTransferEventID = MessageBusABI.Events["ValueTransfer"].ID ) -func lazilyLogReceiptChecksum(msg string, receipts types.Receipts, logger gethlog.Logger) { - logger.Trace(msg, "Hash", +func lazilyLogReceiptChecksum(block *common.L1Block, receipts types.Receipts, logger gethlog.Logger) { + logger.Trace("Processing block", log.BlockHashKey, block.Hash(), "nr_rec", len(receipts), "Hash", gethlog.Lazy{Fn: func() string { hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) hasher.Reset() diff --git a/go/enclave/enclave.go b/go/enclave/enclave.go index 21c5d79cc7..91c380b70e 100644 --- a/go/enclave/enclave.go +++ b/go/enclave/enclave.go @@ -89,6 +89,7 @@ type enclaveImpl struct { dataEncryptionService crypto.DataEncryptionService dataCompressionService compression.DataCompressionService + gethEncodingService gethencoding.EncodingService profiler *profiler.Profiler debugger *debugger.Debugger logger gethlog.Logger @@ -171,6 +172,7 @@ func NewEnclave( obscuroKey := crypto.GetObscuroKey(logger) rpcEncryptionManager := rpc.NewEncryptionManager(ecies.ImportECDSA(obscuroKey)) + gethEncodingService := gethencoding.NewGethEncodingService(storage, logger) dataEncryptionService := crypto.NewDataEncryptionService(logger) dataCompressionService := compression.NewBrotliDataCompressionService() @@ -180,18 +182,18 @@ func NewEnclave( gasOracle := gas.NewGasOracle() blockProcessor := components.NewBlockProcessor(storage, crossChainProcessors, gasOracle, logger) - batchExecutor := components.NewBatchExecutor(storage, crossChainProcessors, genesis, gasOracle, chainConfig, config.GasBatchExecutionLimit, logger) + batchExecutor := components.NewBatchExecutor(storage, gethEncodingService, crossChainProcessors, genesis, gasOracle, chainConfig, config.GasBatchExecutionLimit, logger) sigVerifier, err := components.NewSignatureValidator(config.SequencerID, storage) registry := components.NewBatchRegistry(storage, logger) rProducer := components.NewRollupProducer(config.SequencerID, storage, registry, logger) if err != nil { logger.Crit("Could not initialise the signature validator", log.ErrKey, err) } - rollupCompression := components.NewRollupCompression(registry, batchExecutor, dataEncryptionService, dataCompressionService, storage, chainConfig, logger) + rollupCompression := components.NewRollupCompression(registry, batchExecutor, dataEncryptionService, dataCompressionService, storage, gethEncodingService, chainConfig, logger) rConsumer := components.NewRollupConsumer(mgmtContractLib, registry, rollupCompression, storage, logger, sigVerifier) sharedSecretProcessor := components.NewSharedSecretProcessor(mgmtContractLib, attestationProvider, storage, logger) - blockchain := ethchainadapter.NewEthChainAdapter(big.NewInt(config.ObscuroChainID), registry, storage, logger) + blockchain := ethchainadapter.NewEthChainAdapter(big.NewInt(config.ObscuroChainID), registry, storage, gethEncodingService, logger) mempool, err := txpool.NewTxPool(blockchain, config.MinGasPrice, logger) if err != nil { logger.Crit("unable to init eth tx pool", log.ErrKey, err) @@ -206,6 +208,7 @@ func NewEnclave( rProducer, rConsumer, rollupCompression, + gethEncodingService, logger, config.HostID, chainConfig, @@ -229,6 +232,7 @@ func NewEnclave( chain := l2chain.NewChain( storage, + gethEncodingService, chainConfig, genesis, logger, @@ -263,6 +267,7 @@ func NewEnclave( enclavePubKey: serializedEnclavePubKey, dataEncryptionService: dataEncryptionService, dataCompressionService: dataCompressionService, + gethEncodingService: gethEncodingService, profiler: prof, logger: logger, debugger: debug, @@ -537,11 +542,17 @@ func (e *enclaveImpl) SubmitBatch(extBatch *common.ExtBatch) common.SystemError return responses.ToInternalError(fmt.Errorf("invalid batch received. Could not verify signature. Cause: %w", err)) } + // calculate the converted hash, and store it in the db for chaining of the converted chain + convertedHeader, err := e.gethEncodingService.CreateEthHeaderForBatch(extBatch.Header) + if err != nil { + return err + } + e.mainMutex.Lock() defer e.mainMutex.Unlock() - // if the signature is valid, then store the batch - err = e.storage.StoreBatch(batch) + // if the signature is valid, then store the batch together with the converted hash + err = e.storage.StoreBatch(batch, convertedHeader.Hash()) if err != nil { return responses.ToInternalError(fmt.Errorf("could not store batch. Cause: %w", err)) } diff --git a/go/enclave/events/subscription_manager.go b/go/enclave/events/subscription_manager.go index 170f4f980d..91e675bf17 100644 --- a/go/enclave/events/subscription_manager.go +++ b/go/enclave/events/subscription_manager.go @@ -6,6 +6,8 @@ import ( "math/big" "sync" + "github.com/ten-protocol/go-ten/go/common/log" + "github.com/ten-protocol/go-ten/go/enclave/core" "github.com/ten-protocol/go-ten/go/enclave/storage" @@ -153,7 +155,7 @@ func (s *SubscriptionManager) GetSubscribedLogsForBatch(batch *core.Batch, recei if relevant { relevantLogsForSub = append(relevantLogsForSub, logItem) } - s.logger.Debug(fmt.Sprintf("Subscription %s. Account %s. Log %v. Extracted addresses: %v. Relevant: %t", id, sub.Account, logItem, userAddrs, relevant)) + s.logger.Debug("Subscription", log.SubIDKey, id, "acc", sub.Account, "log", logItem, "extr_addr", userAddrs, "relev", relevant) } if len(relevantLogsForSub) > 0 { relevantLogsPerSubscription[id] = relevantLogsForSub @@ -239,21 +241,21 @@ func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []geth Logs: for _, logItem := range logs { if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > logItem.BlockNumber { - logger.Debug(fmt.Sprintf("Skipping log = %v", logItem), "reason", "In the past. The starting block num for filter is bigger than log") + logger.Debug("Skipping log ", "log", logItem, "reason", "In the past. The starting block num for filter is bigger than log") continue } if toBlock != nil && toBlock.Int64() > 0 && toBlock.Uint64() < logItem.BlockNumber { - logger.Debug(fmt.Sprintf("Skipping log = %v", logItem), "reason", "In the future. The ending block num for filter is smaller than log") + logger.Debug("Skipping log ", "log", logItem, "reason", "In the future. The ending block num for filter is smaller than log") continue } if len(addresses) > 0 && !includes(addresses, logItem.Address) { - logger.Debug(fmt.Sprintf("Skipping log = %v", logItem), "reason", "The contract address of the log is not an address of interest") + logger.Debug("Skipping log ", "log", logItem, "reason", "The contract address of the log is not an address of interest") continue } // If the to filtered topics is greater than the amount of topics in logs, skip. if len(topics) > len(logItem.Topics) { - logger.Debug(fmt.Sprintf("Skipping log = %v", logItem), "reason", "Insufficient topics. The log has less topics than the required one to satisfy the query") + logger.Debug("Skipping log ", "log", logItem, "reason", "Insufficient topics. The log has less topics than the required one to satisfy the query") continue } for i, sub := range topics { @@ -265,7 +267,7 @@ Logs: } } if !match { - logger.Debug(fmt.Sprintf("Skipping log = %v", logItem), "reason", "Topics do not match.") + logger.Debug("Skipping log ", "log", logItem, "reason", "Topics do not match.") continue Logs } } diff --git a/go/enclave/evm/chain_context.go b/go/enclave/evm/chain_context.go index 1eae4dd92a..31941479d7 100644 --- a/go/enclave/evm/chain_context.go +++ b/go/enclave/evm/chain_context.go @@ -16,15 +16,17 @@ import ( // ObscuroChainContext - basic implementation of the ChainContext needed for the EVM integration type ObscuroChainContext struct { - storage storage.Storage - logger gethlog.Logger + storage storage.Storage + gethEncodingService gethencoding.EncodingService + logger gethlog.Logger } // NewObscuroChainContext returns a new instance of the ObscuroChainContext given a storage ( and logger ) -func NewObscuroChainContext(storage storage.Storage, logger gethlog.Logger) *ObscuroChainContext { +func NewObscuroChainContext(storage storage.Storage, gethEncodingService gethencoding.EncodingService, logger gethlog.Logger) *ObscuroChainContext { return &ObscuroChainContext{ - storage: storage, - logger: logger, + storage: storage, + gethEncodingService: gethEncodingService, + logger: logger, } } @@ -41,7 +43,7 @@ func (occ *ObscuroChainContext) GetHeader(hash common.Hash, _ uint64) *types.Hea occ.logger.Crit("Could not retrieve rollup", log.ErrKey, err) } - h, err := gethencoding.CreateEthHeaderForBatch(batch.Header, secret(occ.storage)) + h, err := occ.gethEncodingService.CreateEthHeaderForBatch(batch.Header) if err != nil { occ.logger.Crit("Could not convert to eth header", log.ErrKey, err) return nil diff --git a/go/enclave/evm/ethchainadapter/eth_chainadapter.go b/go/enclave/evm/ethchainadapter/eth_chainadapter.go index d90073a193..7ac12e930f 100644 --- a/go/enclave/evm/ethchainadapter/eth_chainadapter.go +++ b/go/enclave/evm/ethchainadapter/eth_chainadapter.go @@ -3,7 +3,7 @@ package ethchainadapter import ( "math/big" - "github.com/ethereum/go-ethereum/common" + gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/event" @@ -23,17 +23,19 @@ import ( type EthChainAdapter struct { newHeadChan chan gethcore.ChainHeadEvent batchRegistry components.BatchRegistry + gethEncoding gethencoding.EncodingService storage storage.Storage chainID *big.Int logger gethlog.Logger } // NewEthChainAdapter returns a new instance -func NewEthChainAdapter(chainID *big.Int, batchRegistry components.BatchRegistry, storage storage.Storage, logger gethlog.Logger) *EthChainAdapter { +func NewEthChainAdapter(chainID *big.Int, batchRegistry components.BatchRegistry, storage storage.Storage, gethEncoding gethencoding.EncodingService, logger gethlog.Logger) *EthChainAdapter { return &EthChainAdapter{ newHeadChan: make(chan gethcore.ChainHeadEvent), batchRegistry: batchRegistry, storage: storage, + gethEncoding: gethEncoding, chainID: chainID, logger: logger, } @@ -52,10 +54,10 @@ func (e *EthChainAdapter) CurrentBlock() *gethtypes.Header { } currentBatch, err := e.storage.FetchBatchBySeqNo(currentBatchSeqNo.Uint64()) if err != nil { - e.logger.Warn("unable to retrieve batch seq no: %d", "currentBatchSeqNo", currentBatchSeqNo, log.ErrKey, err) + e.logger.Warn("unable to retrieve batch seq no", "currentBatchSeqNo", currentBatchSeqNo, log.ErrKey, err) return nil } - batch, err := gethencoding.CreateEthHeaderForBatch(currentBatch.Header, secret(e.storage)) + batch, err := e.gethEncoding.CreateEthHeaderForBatch(currentBatch.Header) if err != nil { e.logger.Warn("unable to convert batch to eth header ", "currentBatchSeqNo", currentBatchSeqNo, log.ErrKey, err) return nil @@ -81,7 +83,7 @@ func (e *EthChainAdapter) SubscribeChainHeadEvent(ch chan<- gethcore.ChainHeadEv } // GetBlock retrieves a specific block, used during pool resets. -func (e *EthChainAdapter) GetBlock(_ common.Hash, number uint64) *gethtypes.Block { +func (e *EthChainAdapter) GetBlock(_ gethcommon.Hash, number uint64) *gethtypes.Block { var batch *core.Batch // to avoid a costly select to the db, check whether the batches requested are the last ones which are cached @@ -106,7 +108,7 @@ func (e *EthChainAdapter) GetBlock(_ common.Hash, number uint64) *gethtypes.Bloc } } - nfromBatch, err := gethencoding.CreateEthBlockFromBatch(batch) + nfromBatch, err := e.gethEncoding.CreateEthBlockFromBatch(batch) if err != nil { e.logger.Error("unable to convert batch to eth block", log.ErrKey, err) return nil @@ -116,7 +118,7 @@ func (e *EthChainAdapter) GetBlock(_ common.Hash, number uint64) *gethtypes.Bloc } // StateAt returns a state database for a given root hash (generally the head). -func (e *EthChainAdapter) StateAt(root common.Hash) (*state.StateDB, error) { +func (e *EthChainAdapter) StateAt(root gethcommon.Hash) (*state.StateDB, error) { if root.Hex() == gethtypes.EmptyCodeHash.Hex() { return nil, nil //nolint:nilnil } @@ -125,7 +127,7 @@ func (e *EthChainAdapter) StateAt(root common.Hash) (*state.StateDB, error) { } func (e *EthChainAdapter) IngestNewBlock(batch *core.Batch) error { - convertedBlock, err := gethencoding.CreateEthBlockFromBatch(batch) + convertedBlock, err := e.gethEncoding.CreateEthBlockFromBatch(batch) if err != nil { return err } @@ -152,9 +154,3 @@ func NewLegacyPoolConfig() legacypool.Config { Lifetime: legacypool.DefaultConfig.Lifetime, } } - -func secret(storage storage.Storage) []byte { - // todo (#1053) - handle secret not being found. - secret, _ := storage.FetchSecret() - return secret[:] -} diff --git a/go/enclave/evm/evm_facade.go b/go/enclave/evm/evm_facade.go index 31560d705c..6d3153afce 100644 --- a/go/enclave/evm/evm_facade.go +++ b/go/enclave/evm/evm_facade.go @@ -34,19 +34,20 @@ func ExecuteTransactions( s *state.StateDB, header *common.BatchHeader, storage storage.Storage, + gethEncodingService gethencoding.EncodingService, chainConfig *params.ChainConfig, fromTxIndex int, noBaseFee bool, batchGasLimit uint64, logger gethlog.Logger, -) map[common.TxHash]interface{} { - chain, vmCfg := initParams(storage, noBaseFee, logger) +) map[common.TxHash]interface{} { // todo - return error + chain, vmCfg := initParams(storage, gethEncodingService, noBaseFee, logger) gp := gethcore.GasPool(batchGasLimit) zero := uint64(0) usedGas := &zero result := map[common.TxHash]interface{}{} - ethHeader, err := gethencoding.CreateEthHeaderForBatch(header, secret(storage)) + ethHeader, err := gethEncodingService.CreateEthHeaderForBatch(header) if err != nil { logger.Crit("Could not convert to eth header", log.ErrKey, err) return nil @@ -157,6 +158,7 @@ func ExecuteObsCall( s *state.StateDB, header *common.BatchHeader, storage storage.Storage, + gethEncodingService gethencoding.EncodingService, chainConfig *params.ChainConfig, gasEstimationCap uint64, logger gethlog.Logger, @@ -170,8 +172,9 @@ func ExecuteObsCall( gp := gethcore.GasPool(gasEstimationCap) gp.SetGas(gasEstimationCap) - chain, vmCfg := initParams(storage, noBaseFee, nil) - ethHeader, err := gethencoding.CreateEthHeaderForBatch(header, secret(storage)) + chain, vmCfg := initParams(storage, gethEncodingService, noBaseFee, nil) + + ethHeader, err := gethEncodingService.CreateEthHeaderForBatch(header) if err != nil { return nil, err } @@ -206,19 +209,11 @@ func ExecuteObsCall( return result, nil } -func initParams(storage storage.Storage, noBaseFee bool, l gethlog.Logger) (*ObscuroChainContext, vm.Config) { +func initParams(storage storage.Storage, gethEncodingService gethencoding.EncodingService, noBaseFee bool, l gethlog.Logger) (*ObscuroChainContext, vm.Config) { vmCfg := vm.Config{ NoBaseFee: noBaseFee, } - return NewObscuroChainContext(storage, l), vmCfg -} - -// todo (#1053) - this is currently just returning the shared secret -// it should not use it directly, but derive some entropy from it -func secret(storage storage.Storage) []byte { - // todo (#1053) - handle secret not being found. - secret, _ := storage.FetchSecret() - return secret[:] + return NewObscuroChainContext(storage, gethEncodingService, l), vmCfg } func newErrorWithReasonAndCode(err error) error { diff --git a/go/enclave/l2chain/l2_chain.go b/go/enclave/l2chain/l2_chain.go index 7f56e0fde6..37398b7649 100644 --- a/go/enclave/l2chain/l2_chain.go +++ b/go/enclave/l2chain/l2_chain.go @@ -29,8 +29,9 @@ import ( type obscuroChain struct { chainConfig *params.ChainConfig - storage storage.Storage - genesis *genesis.Genesis + storage storage.Storage + gethEncodingService gethencoding.EncodingService + genesis *genesis.Genesis logger gethlog.Logger @@ -40,6 +41,7 @@ type obscuroChain struct { func NewChain( storage storage.Storage, + gethEncodingService gethencoding.EncodingService, chainConfig *params.ChainConfig, genesis *genesis.Genesis, logger gethlog.Logger, @@ -47,12 +49,13 @@ func NewChain( gasEstimationCap uint64, ) ObscuroChain { return &obscuroChain{ - storage: storage, - chainConfig: chainConfig, - logger: logger, - genesis: genesis, - Registry: registry, - gasEstimationCap: gasEstimationCap, + storage: storage, + gethEncodingService: gethEncodingService, + chainConfig: chainConfig, + logger: logger, + genesis: genesis, + Registry: registry, + gasEstimationCap: gasEstimationCap, } } @@ -147,7 +150,7 @@ func (oc *obscuroChain) ObsCallAtBlock(apiArgs *gethapi.TransactionArgs, blockNu batch.Header.Root.Hex()) }}) - result, err := evm.ExecuteObsCall(callMsg, blockState, batch.Header, oc.storage, oc.chainConfig, oc.gasEstimationCap, oc.logger) + result, err := evm.ExecuteObsCall(callMsg, blockState, batch.Header, oc.storage, oc.gethEncodingService, oc.chainConfig, oc.gasEstimationCap, oc.logger) if err != nil { // also return the result as the result can be evaluated on some errors like ErrIntrinsicGas return result, err @@ -191,8 +194,9 @@ func (oc *obscuroChain) GetChainStateAtTransaction(batch *core.Batch, txIndex in } txContext := gethcore.NewEVMTxContext(msg) - chain := evm.NewObscuroChainContext(oc.storage, oc.logger) - blockHeader, err := gethencoding.CreateEthHeaderForBatch(batch.Header, nil) + chain := evm.NewObscuroChainContext(oc.storage, oc.gethEncodingService, oc.logger) + + blockHeader, err := oc.gethEncodingService.CreateEthHeaderForBatch(batch.Header) if err != nil { return nil, vm.BlockContext{}, nil, fmt.Errorf("unable to convert batch header to eth header - %w", err) } diff --git a/go/enclave/nodetype/sequencer.go b/go/enclave/nodetype/sequencer.go index 0fe421f1a3..e4824ead36 100644 --- a/go/enclave/nodetype/sequencer.go +++ b/go/enclave/nodetype/sequencer.go @@ -9,6 +9,8 @@ import ( "sort" "time" + "github.com/ten-protocol/go-ten/go/common/gethencoding" + "github.com/ethereum/go-ethereum/core/types" "github.com/ten-protocol/go-ten/go/common/errutil" "github.com/ten-protocol/go-ten/go/common/measure" @@ -46,6 +48,7 @@ type sequencer struct { rollupProducer components.RollupProducer rollupConsumer components.RollupConsumer rollupCompression *components.RollupCompression + gethEncoding gethencoding.EncodingService logger gethlog.Logger @@ -60,24 +63,7 @@ type sequencer struct { blockchain *ethchainadapter.EthChainAdapter } -func NewSequencer( - blockProcessor components.L1BlockProcessor, - batchExecutor components.BatchExecutor, - registry components.BatchRegistry, - rollupProducer components.RollupProducer, - rollupConsumer components.RollupConsumer, - rollupCompression *components.RollupCompression, - logger gethlog.Logger, - hostID gethcommon.Address, - chainConfig *params.ChainConfig, - enclavePrivateKey *ecdsa.PrivateKey, - mempool *txpool.TxPool, - storage storage.Storage, - dataEncryptionService crypto.DataEncryptionService, - dataCompressionService compression.DataCompressionService, - settings SequencerSettings, - blockchain *ethchainadapter.EthChainAdapter, -) Sequencer { +func NewSequencer(blockProcessor components.L1BlockProcessor, batchExecutor components.BatchExecutor, registry components.BatchRegistry, rollupProducer components.RollupProducer, rollupConsumer components.RollupConsumer, rollupCompression *components.RollupCompression, gethEncodingService gethencoding.EncodingService, logger gethlog.Logger, hostID gethcommon.Address, chainConfig *params.ChainConfig, enclavePrivateKey *ecdsa.PrivateKey, mempool *txpool.TxPool, storage storage.Storage, dataEncryptionService crypto.DataEncryptionService, dataCompressionService compression.DataCompressionService, settings SequencerSettings, blockchain *ethchainadapter.EthChainAdapter) Sequencer { return &sequencer{ blockProcessor: blockProcessor, batchProducer: batchExecutor, @@ -85,6 +71,7 @@ func NewSequencer( rollupProducer: rollupProducer, rollupConsumer: rollupConsumer, rollupCompression: rollupCompression, + gethEncoding: gethEncodingService, logger: logger, hostID: hostID, chainConfig: chainConfig, @@ -312,7 +299,12 @@ func (s *sequencer) StoreExecutedBatch(batch *core.Batch, receipts types.Receipt return nil } - if err := s.storage.StoreBatch(batch); err != nil { + convertedHeader, err := s.gethEncoding.CreateEthHeaderForBatch(batch.Header) + if err != nil { + return err + } + + if err := s.storage.StoreBatch(batch, convertedHeader.Hash()); err != nil { return fmt.Errorf("failed to store batch. Cause: %w", err) } diff --git a/go/enclave/storage/db_cache.go b/go/enclave/storage/db_cache.go deleted file mode 100644 index 555e2b060e..0000000000 --- a/go/enclave/storage/db_cache.go +++ /dev/null @@ -1,39 +0,0 @@ -package storage - -import ( - "context" - - "github.com/eko/gocache/lib/v4/cache" - gethlog "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ten-protocol/go-ten/go/common/log" -) - -func getCachedValue[V any](cache *cache.Cache[[]byte], logger gethlog.Logger, key any, onFailed func(any) (V, error)) (V, error) { - value, err := cache.Get(context.Background(), key) - if err != nil { - // todo metrics for cache misses - b, err := onFailed(key) - if err != nil { - return b, err - } - cacheValue(cache, logger, key, b) - return b, err - } - - v := new(V) - err = rlp.DecodeBytes(value, v) - return *v, err -} - -func cacheValue(cache *cache.Cache[[]byte], logger gethlog.Logger, key any, v any) { - encoded, err := rlp.EncodeToBytes(v) - if err != nil { - logger.Error("Could not encode value to store in cache", log.ErrKey, err) - return - } - err = cache.Set(context.Background(), key, encoded) - if err != nil { - logger.Error("Could not store value in cache", log.ErrKey, err) - } -} diff --git a/go/enclave/storage/enclavedb/batch.go b/go/enclave/storage/enclavedb/batch.go index eddc7988c9..3866fa9f1d 100644 --- a/go/enclave/storage/enclavedb/batch.go +++ b/go/enclave/storage/enclavedb/batch.go @@ -25,7 +25,7 @@ const ( txInsert = "replace into tx values " txInsertValue = "(?,?,?,?,?,?,?)" - bInsert = "insert into batch values (?,?,?,?,?,?,?,?,?,?)" + batchInsert = "insert into batch values (?,?,?,?,?,?,?,?,?,?,?)" updateBatchExecuted = "update batch set is_executed=true where sequence=?" selectBatch = "select b.header, bb.content from batch b join batch_body bb on b.body=bb.id" @@ -49,7 +49,7 @@ const ( ) // WriteBatchAndTransactions - persists the batch and the transactions -func WriteBatchAndTransactions(dbtx DBTransaction, batch *core.Batch) error { +func WriteBatchAndTransactions(dbtx DBTransaction, batch *core.Batch, convertedHash gethcommon.Hash) error { // todo - optimize for reorgs batchBodyID := batch.SeqNo().Uint64() @@ -77,9 +77,10 @@ func WriteBatchAndTransactions(dbtx DBTransaction, batch *core.Batch) error { isCanon = false } - dbtx.ExecuteSQL(bInsert, + dbtx.ExecuteSQL(batchInsert, batch.Header.SequencerOrderNo.Uint64(), // sequence batch.Hash(), // full hash + convertedHash, // converted_hash truncTo16(batch.Hash()), // index hash parentBytes, // parent batch.Header.Number.Uint64(), // height @@ -545,3 +546,18 @@ func GetPublicTransactionCount(db *sql.DB) (uint64, error) { return count, nil } + +func FetchConvertedBatchHash(db *sql.DB, seqNo uint64) (gethcommon.Hash, error) { + var hash []byte + + query := "select converted_hash from batch where sequence=?" + err := db.QueryRow(query, seqNo).Scan(&hash) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + // make sure the error is converted to obscuro-wide not found error + return gethcommon.Hash{}, errutil.ErrNotFound + } + return gethcommon.Hash{}, err + } + return gethcommon.BytesToHash(hash), nil +} diff --git a/go/enclave/storage/init/edgelessdb/001_init.sql b/go/enclave/storage/init/edgelessdb/001_init.sql index 098ff49602..4b972628be 100644 --- a/go/enclave/storage/init/edgelessdb/001_init.sql +++ b/go/enclave/storage/init/edgelessdb/001_init.sql @@ -74,6 +74,7 @@ create table if not exists obsdb.batch ( sequence int, full_hash binary(32), + converted_hash binary(32) NOT NULL, hash binary(16) NOT NULL, parent binary(16), height int NOT NULL, diff --git a/go/enclave/storage/init/sqlite/001_init.sql b/go/enclave/storage/init/sqlite/001_init.sql index f032f7a039..d96bcebd69 100644 --- a/go/enclave/storage/init/sqlite/001_init.sql +++ b/go/enclave/storage/init/sqlite/001_init.sql @@ -34,9 +34,9 @@ create index IDX_BLOCK_HEIGHT on block (height); create table if not exists l1_msg ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - message varbinary(1024) NOT NULL, - block binary(16) NOT NULL REFERENCES block, + id INTEGER PRIMARY KEY AUTOINCREMENT, + message varbinary(1024) NOT NULL, + block binary(16) NOT NULL REFERENCES block, is_transfer boolean ); @@ -57,16 +57,17 @@ create table if not exists batch_body create table if not exists batch ( - sequence int primary key, - full_hash binary(32), - hash binary(16) NOT NULL unique, - parent binary(16), - height int NOT NULL, - is_canonical boolean NOT NULL, - header blob NOT NULL, - body int NOT NULL REFERENCES batch_body, - l1_proof binary(16) NOT NULL, -- normally this would be a FK, but there is a weird edge case where an L2 node might not have the block used to create this batch - is_executed boolean NOT NULL + sequence int primary key, + full_hash binary(32), + converted_hash binary(32), + hash binary(16) NOT NULL unique, + parent binary(16), + height int NOT NULL, + is_canonical boolean NOT NULL, + header blob NOT NULL, + body int NOT NULL REFERENCES batch_body, + l1_proof binary(16) NOT NULL, -- normally this would be a FK, but there is a weird edge case where an L2 node might not have the block used to create this batch + is_executed boolean NOT NULL -- the unique constraint is commented for now because there might be multiple non-canonical batches for the same height -- unique (height, is_canonical, is_executed) ); diff --git a/go/enclave/storage/interfaces.go b/go/enclave/storage/interfaces.go index 61471e0d46..713c4e25ff 100644 --- a/go/enclave/storage/interfaces.go +++ b/go/enclave/storage/interfaces.go @@ -55,6 +55,8 @@ type BatchResolver interface { // FetchCanonicalUnexecutedBatches - return the list of the unexecuted batches that are canonical FetchCanonicalUnexecutedBatches(*big.Int) ([]*core.Batch, error) + FetchConvertedHash(hash common.L2BatchHash) (gethcommon.Hash, error) + // BatchWasExecuted - return true if the batch was executed BatchWasExecuted(hash common.L2BatchHash) (bool, error) @@ -62,7 +64,7 @@ type BatchResolver interface { FetchHeadBatchForBlock(blockHash common.L1BlockHash) (*core.Batch, error) // StoreBatch stores an un-executed batch. - StoreBatch(batch *core.Batch) error + StoreBatch(batch *core.Batch, convertedHash gethcommon.Hash) error // StoreExecutedBatch - store the batch after it was executed StoreExecutedBatch(batch *core.Batch, receipts []*types.Receipt) error diff --git a/go/enclave/storage/storage.go b/go/enclave/storage/storage.go index d270f9263d..b9760d81bb 100644 --- a/go/enclave/storage/storage.go +++ b/go/enclave/storage/storage.go @@ -2,18 +2,17 @@ package storage import ( "bytes" - "context" "crypto/ecdsa" "errors" "fmt" "math/big" "time" + "github.com/dgraph-io/ristretto" + "github.com/eko/gocache/lib/v4/cache" "github.com/ten-protocol/go-ten/go/common/measure" - "github.com/allegro/bigcache/v3" - "github.com/eko/gocache/lib/v4/cache" - bigcache_store "github.com/eko/gocache/store/bigcache/v4" + ristretto_store "github.com/eko/gocache/store/ristretto/v4" "github.com/ten-protocol/go-ten/go/config" @@ -50,12 +49,15 @@ type storageImpl struct { // cache for the immutable blocks and batches. // this avoids a trip to the database. - blockCache *cache.Cache[[]byte] + blockCache *cache.Cache[*types.Block] // stores batches using the sequence number as key // stores a mapping between the hash and the sequence number // to fetch a batch by hash will require 2 cache hits - batchCache *cache.Cache[[]byte] + batchCache *cache.Cache[*core.Batch] + batchSeqCache *cache.Cache[*big.Int] + + cachedSharedSecret *crypto.SharedEnclaveSecret stateDB state.Database chainConfig *params.ChainConfig @@ -80,27 +82,26 @@ func NewStorage(backingDB enclavedb.EnclaveDB, chainConfig *params.ChainConfig, } // todo (tudor) figure out the context and the config - cfg := bigcache.DefaultConfig(2 * time.Minute) - cfg.Shards = 512 - // 1GB cache. Max value in a shard is 2MB. No batch or block should be larger than that - cfg.HardMaxCacheSize = cfg.Shards * 4 - bigcacheClient, err := bigcache.New(context.Background(), cfg) + ristrettoCache, err := ristretto.NewCache(&ristretto.Config{ + NumCounters: 10_000, // number of keys to track frequency of. + MaxCost: 1 << 30, // maximum cost of cache (1GB). + BufferItems: 64, // number of keys per Get buffer. + }) if err != nil { - logger.Crit("Could not initialise bigcache", log.ErrKey, err) + logger.Crit("Could not initialise ristretto cache", log.ErrKey, err) } - - bigcacheStore := bigcache_store.NewBigcache(bigcacheClient) - + ristrettoStore := ristretto_store.NewRistretto(ristrettoCache) return &storageImpl{ db: backingDB, stateDB: state.NewDatabaseWithConfig(backingDB, &trie.Config{ Cache: cacheConfig.TrieCleanLimit, Preimages: cacheConfig.Preimages, }), - chainConfig: chainConfig, - batchCache: cache.New[[]byte](bigcacheStore), - blockCache: cache.New[[]byte](bigcacheStore), - logger: logger, + chainConfig: chainConfig, + batchCache: cache.New[*core.Batch](ristrettoStore), + batchSeqCache: cache.New[*big.Int](ristrettoStore), + blockCache: cache.New[*types.Block](ristrettoStore), + logger: logger, } } @@ -128,12 +129,12 @@ func (s *storageImpl) FetchCurrentSequencerNo() (*big.Int, error) { func (s *storageImpl) FetchBatch(hash common.L2BatchHash) (*core.Batch, error) { defer s.logDuration("FetchBatch", measure.NewStopwatch()) - seqNo, err := getCachedValue(s.batchCache, s.logger, hash, func(v any) (*big.Int, error) { + seqNo, err := common.GetCachedValue(s.batchSeqCache, s.logger, hash, func(v any) (*big.Int, error) { batch, err := enclavedb.ReadBatchByHash(s.db.GetSQLDB(), v.(common.L2BatchHash)) if err != nil { return nil, err } - cacheValue(s.batchCache, s.logger, batch.SeqNo(), batch) + common.CacheValue(s.batchCache, s.logger, batch.SeqNo(), batch) return batch.SeqNo(), nil }) if err != nil { @@ -142,6 +143,15 @@ func (s *storageImpl) FetchBatch(hash common.L2BatchHash) (*core.Batch, error) { return s.FetchBatchBySeqNo(seqNo.Uint64()) } +func (s *storageImpl) FetchConvertedHash(hash common.L2BatchHash) (gethcommon.Hash, error) { + defer s.logDuration("FetchConvertedHash", measure.NewStopwatch()) + batch, err := s.FetchBatch(hash) + if err != nil { + return gethcommon.Hash{}, err + } + return enclavedb.FetchConvertedBatchHash(s.db.GetSQLDB(), batch.Header.SequencerOrderNo.Uint64()) +} + func (s *storageImpl) FetchBatchHeader(hash common.L2BatchHash) (*common.BatchHeader, error) { defer s.logDuration("FetchBatchHeader", measure.NewStopwatch()) b, err := s.FetchBatch(hash) @@ -180,14 +190,14 @@ func (s *storageImpl) StoreBlock(b *types.Block, chainFork *common.ChainFork) er return fmt.Errorf("3. could not store block %s. Cause: %w", b.Hash(), err) } - cacheValue(s.blockCache, s.logger, b.Hash(), b) + common.CacheValue(s.blockCache, s.logger, b.Hash(), b) return nil } func (s *storageImpl) FetchBlock(blockHash common.L1BlockHash) (*types.Block, error) { defer s.logDuration("FetchBlock", measure.NewStopwatch()) - return getCachedValue(s.blockCache, s.logger, blockHash, func(hash any) (*types.Block, error) { + return common.GetCachedValue(s.blockCache, s.logger, blockHash, func(hash any) (*types.Block, error) { return enclavedb.FetchBlock(s.db.GetSQLDB(), hash.(common.L1BlockHash)) }) } @@ -221,6 +231,11 @@ func (s *storageImpl) StoreSecret(secret crypto.SharedEnclaveSecret) error { func (s *storageImpl) FetchSecret() (*crypto.SharedEnclaveSecret, error) { defer s.logDuration("FetchSecret", measure.NewStopwatch()) + + if s.cachedSharedSecret != nil { + return s.cachedSharedSecret, nil + } + var ss crypto.SharedEnclaveSecret cfg, err := enclavedb.FetchConfig(s.db.GetSQLDB(), masterSeedCfg) @@ -231,7 +246,8 @@ func (s *storageImpl) FetchSecret() (*crypto.SharedEnclaveSecret, error) { return nil, fmt.Errorf("could not decode shared secret") } - return &ss, nil + s.cachedSharedSecret = &ss + return s.cachedSharedSecret, nil } func (s *storageImpl) IsAncestor(block *types.Block, maybeAncestor *types.Block) bool { @@ -349,7 +365,7 @@ func (s *storageImpl) StoreAttestedKey(aggregator gethcommon.Address, key *ecdsa func (s *storageImpl) FetchBatchBySeqNo(seqNum uint64) (*core.Batch, error) { defer s.logDuration("FetchBatchBySeqNo", measure.NewStopwatch()) - return getCachedValue(s.batchCache, s.logger, seqNum, func(seq any) (*core.Batch, error) { + return common.GetCachedValue(s.batchCache, s.logger, seqNum, func(seq any) (*core.Batch, error) { return enclavedb.ReadBatchBySeqNo(s.db.GetSQLDB(), seq.(uint64)) }) } @@ -359,7 +375,7 @@ func (s *storageImpl) FetchBatchesByBlock(block common.L1BlockHash) ([]*core.Bat return enclavedb.ReadBatchesByBlock(s.db.GetSQLDB(), block) } -func (s *storageImpl) StoreBatch(batch *core.Batch) error { +func (s *storageImpl) StoreBatch(batch *core.Batch, convertedHash gethcommon.Hash) error { defer s.logDuration("StoreBatch", measure.NewStopwatch()) // sanity check that this is not overlapping existingBatchWithSameSequence, _ := s.FetchBatchBySeqNo(batch.SeqNo().Uint64()) @@ -376,7 +392,8 @@ func (s *storageImpl) StoreBatch(batch *core.Batch) error { dbTx := s.db.NewDBTransaction() s.logger.Trace("write batch", log.BatchHashKey, batch.Hash(), "l1Proof", batch.Header.L1Proof, log.BatchSeqNoKey, batch.SeqNo()) - if err := enclavedb.WriteBatchAndTransactions(dbTx, batch); err != nil { + + if err := enclavedb.WriteBatchAndTransactions(dbTx, batch, convertedHash); err != nil { return fmt.Errorf("could not write batch. Cause: %w", err) } @@ -384,8 +401,8 @@ func (s *storageImpl) StoreBatch(batch *core.Batch) error { return fmt.Errorf("could not commit batch %w", err) } - cacheValue(s.batchCache, s.logger, batch.SeqNo(), batch) - cacheValue(s.batchCache, s.logger, batch.Hash(), batch.SeqNo()) + common.CacheValue(s.batchCache, s.logger, batch.SeqNo(), batch) + common.CacheValue(s.batchSeqCache, s.logger, batch.Hash(), batch.SeqNo()) return nil } diff --git a/go/enclave/txpool/txpool_mock_test.go b/go/enclave/txpool/txpool_mock_test.go deleted file mode 100644 index 81693bbba3..0000000000 --- a/go/enclave/txpool/txpool_mock_test.go +++ /dev/null @@ -1,351 +0,0 @@ -package txpool - -import ( - "crypto/ecdsa" - "math/big" - - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/trie" - "github.com/ten-protocol/go-ten/go/common" - "github.com/ten-protocol/go-ten/go/common/errutil" - "github.com/ten-protocol/go-ten/go/common/tracers" - "github.com/ten-protocol/go-ten/go/enclave/core" - "github.com/ten-protocol/go-ten/go/enclave/crypto" - "github.com/ten-protocol/go-ten/go/enclave/limiters" - - gethcommon "github.com/ethereum/go-ethereum/common" -) - -type mockBatchRegistry struct { - currentBatch *core.Batch -} - -func (m *mockBatchRegistry) BatchesAfter(_ uint64, _ uint64, _ limiters.RollupLimiter) ([]*core.Batch, []*types.Block, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) GetBatchStateAtHeight(_ *rpc.BlockNumber) (*state.StateDB, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) GetBatchAtHeight(_ rpc.BlockNumber) (*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) SubscribeForExecutedBatches(_ func(*core.Batch, types.Receipts)) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) UnsubscribeFromBatches() { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) OnBatchExecuted(batch *core.Batch, _ types.Receipts) { - m.currentBatch = batch -} - -func (m *mockBatchRegistry) HasGenesisBatch() (bool, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) HealthCheck() (bool, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockBatchRegistry) HeadBatchSeq() *big.Int { - return m.currentBatch.SeqNo() -} - -func newMockBatchRegistry() *mockBatchRegistry { - return &mockBatchRegistry{} -} - -type mockStorage struct { - currentBatch *core.Batch - batchesSeqNo map[uint64]*core.Batch - batchesHeight map[uint64]*core.Batch - batchesHash map[gethcommon.Hash]*core.Batch - stateDB state.Database -} - -func newMockStorage() *mockStorage { - db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{ - Cache: 1_000_000, - }) - stateDB, err := state.New(types.EmptyRootHash, db, nil) - if err != nil { - panic(err) - } - - _, err = stateDB.Commit(0, true) - if err != nil { - panic(err) - } - - return &mockStorage{ - batchesSeqNo: map[uint64]*core.Batch{}, - batchesHeight: map[uint64]*core.Batch{}, - batchesHash: map[gethcommon.Hash]*core.Batch{}, - stateDB: db, - } -} - -func (m *mockStorage) FetchBlock(_ common.L1BlockHash) (*types.Block, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchCanonicaBlockByHeight(_ *big.Int) (*types.Block, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchHeadBlock() (*types.Block, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreBlock(_ *types.Block, _ *common.ChainFork) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) IsAncestor(_ *types.Block, _ *types.Block) bool { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) IsBlockAncestor(_ *types.Block, _ common.L1BlockHash) bool { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchBatch(_ common.L2BatchHash) (*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchBatchHeader(_ common.L2BatchHash) (*common.BatchHeader, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchBatchByHeight(height uint64) (*core.Batch, error) { - batch, found := m.batchesHeight[height] - if !found { - return nil, errutil.ErrNotFound - } - return batch, nil -} - -func (m *mockStorage) FetchBatchBySeqNo(seqNum uint64) (*core.Batch, error) { - batch, found := m.batchesSeqNo[seqNum] - if !found { - return nil, errutil.ErrNotFound - } - return batch, nil -} - -func (m *mockStorage) FetchHeadBatch() (*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchCurrentSequencerNo() (*big.Int, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchBatchesByBlock(_ common.L1BlockHash) ([]*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchNonCanonicalBatchesBetween(_ uint64, _ uint64) ([]*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchCanonicalUnexecutedBatches(_ *big.Int) ([]*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) BatchWasExecuted(_ common.L2BatchHash) (bool, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchHeadBatchForBlock(_ common.L1BlockHash) (*core.Batch, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreBatch(_ *core.Batch) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreExecutedBatch(batch *core.Batch, _ []*types.Receipt) error { - m.currentBatch = batch - m.batchesSeqNo[batch.SeqNo().Uint64()] = batch - m.batchesHeight[batch.Number().Uint64()] = batch - m.batchesHash[batch.Hash()] = batch - return nil -} - -func (m *mockStorage) StoreRollup(_ *common.ExtRollup, _ *common.CalldataRollupHeader) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchReorgedRollup(_ []common.L1BlockHash) (*common.L2BatchHash, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) CreateStateDB(hash common.L2BatchHash) (*state.StateDB, error) { - batch, found := m.batchesHash[hash] - if !found { - return nil, errutil.ErrNotFound - } - return state.New(batch.Header.Root, m.stateDB, nil) -} - -func (m *mockStorage) EmptyStateDB() (*state.StateDB, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchSecret() (*crypto.SharedEnclaveSecret, error) { - return &crypto.SharedEnclaveSecret{}, nil -} - -func (m *mockStorage) StoreSecret(_ crypto.SharedEnclaveSecret) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetTransaction(_ common.L2TxHash) (*types.Transaction, gethcommon.Hash, uint64, uint64, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetTransactionReceipt(_ common.L2TxHash) (*types.Receipt, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetReceiptsByBatchHash(_ common.L2BatchHash) (types.Receipts, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetContractCreationTx(_ gethcommon.Address) (*gethcommon.Hash, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FetchAttestedKey(_ gethcommon.Address) (*ecdsa.PublicKey, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreAttestedKey(_ gethcommon.Address, _ *ecdsa.PublicKey) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreL1Messages(_ common.L1BlockHash, _ common.CrossChainMessages) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetL1Messages(_ common.L1BlockHash) (common.CrossChainMessages, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreValueTransfers(_ common.L1BlockHash, _ common.ValueTransferEvents) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetL1Transfers(_ common.L1BlockHash) (common.ValueTransferEvents, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StoreEnclaveKey(_ *ecdsa.PrivateKey) error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetEnclaveKey() (*ecdsa.PrivateKey, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetContractCount() (*big.Int, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetReceiptsPerAddress(_ *gethcommon.Address, _ *common.QueryPagination) (types.Receipts, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetPublicTransactionData(_ *common.QueryPagination) ([]common.PublicTransaction, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetPublicTransactionCount() (uint64, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) GetReceiptsPerAddressCount(_ *gethcommon.Address) (uint64, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) Close() error { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) HealthCheck() (bool, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) FilterLogs(_ *gethcommon.Address, _, _ *big.Int, _ *common.L2BatchHash, _ []gethcommon.Address, _ [][]gethcommon.Hash) ([]*types.Log, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) DebugGetLogs(_ common.TxHash) ([]*tracers.DebugLogs, error) { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) TrieDB() *trie.Database { - // TODO implement me - panic("implement me") -} - -func (m *mockStorage) StateDB() state.Database { - return m.stateDB -} diff --git a/go/enclave/txpool/txpool_test.go b/go/enclave/txpool/txpool_test.go deleted file mode 100644 index c5fa2d925a..0000000000 --- a/go/enclave/txpool/txpool_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package txpool - -import ( - "fmt" - "math/big" - "testing" - "time" - - gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/require" - "github.com/ten-protocol/go-ten/go/common" - "github.com/ten-protocol/go-ten/go/enclave/core" - "github.com/ten-protocol/go-ten/go/enclave/evm/ethchainadapter" - "github.com/ten-protocol/go-ten/integration/common/testlog" - "github.com/ten-protocol/go-ten/integration/datagenerator" -) - -func TestTxPool_AddTransaction_Pending(t *testing.T) { - chainID := datagenerator.RandomUInt64() - mockStore := newMockStorage() - mockRegistry := newMockBatchRegistry() - w := datagenerator.RandomWallet(int64(chainID)) - - genesisState, err := applyGenesisState(mockStore, []gethcommon.Address{w.Address()}) - require.NoError(t, err) - genesisBatch := &core.Batch{ - Header: &common.BatchHeader{ - ParentHash: common.L2BatchHash{}, - // L1Proof: common.ha, - Root: genesisState, - TxHash: types.EmptyRootHash, - Number: big.NewInt(int64(0)), - SequencerOrderNo: big.NewInt(int64(common.L2GenesisSeqNo)), // genesis batch has seq number 1 - ReceiptHash: types.EmptyRootHash, - TransfersTree: types.EmptyRootHash, - // Time: timeNow, - // Coinbase: coinbase, - // BaseFee: baseFee, - GasLimit: 1_000_000_000_000, // todo (@siliev) - does the batch header need uint64? - }, - Transactions: []*common.L2Tx{}, - } - - err = mockStore.StoreExecutedBatch(genesisBatch, nil) - require.NoError(t, err) - - mockRegistry.OnBatchExecuted(genesisBatch, nil) - - blockchain := ethchainadapter.NewEthChainAdapter( - big.NewInt(int64(chainID)), - mockRegistry, - mockStore, - testlog.Logger(), - ) - err = blockchain.IngestNewBlock(genesisBatch) - require.NoError(t, err) - - txPool, err := NewTxPool(blockchain, big.NewInt(1), testlog.Logger()) - require.NoError(t, err) - - // Start the TxPool - err = txPool.Start() - require.NoError(t, err) - - // Create and add a transaction - randAddr := datagenerator.RandomAddress() - transaction := &types.LegacyTx{ - Nonce: 0, - Value: big.NewInt(1_000_000_000), - Gas: uint64(1_000_000), - GasPrice: gethcommon.Big1, - To: &randAddr, - } - signedTx, err := w.SignTransaction(transaction) - require.NoError(t, err) - - err = txPool.Add(signedTx) - if err != nil { - t.Fatalf("Failed to add transaction: %v", err) - } - - time.Sleep(time.Second) // make sure the tx makes into the pool - - // Check if the transaction is in pending - pendingTxs := txPool.PendingTransactions() - require.Equal(t, len(pendingTxs), 1) - require.Equal(t, pendingTxs[w.Address()][0].Hash.Hex(), signedTx.Hash().Hex()) - - // TODO Mint a block and check if it's cleared from the pool -} - -func applyGenesisState(storage *mockStorage, accounts []gethcommon.Address) (common.StateRoot, error) { - statedb, err := state.New(types.EmptyRootHash, storage.stateDB, nil) - if err != nil { - return common.StateRoot{}, fmt.Errorf("could not create state DB. Cause: %w", err) - } - - // set the accounts funds - for _, acc := range accounts { - statedb.SetBalance(acc, big.NewInt(1_000_000_000_000_00)) - } - - _ = statedb.IntermediateRoot(true) - commit, err := statedb.Commit(0, true) - if err != nil { - return common.StateRoot{}, err - } - return commit, nil -}