diff --git a/.mockery.yaml b/.mockery.yaml index fc70447..c535f37 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -11,6 +11,13 @@ packages: config: mockname: EthereumClientMock filename: etherman_client.generated.go + github.com/0xPolygon/agglayer/silencer: + config: + interfaces: + ISilencer: + config: + mockname: SilencerMock + filename: silencer.generated.go github.com/0xPolygon/agglayer/types: config: interfaces: @@ -30,7 +37,7 @@ packages: config: mockname: ZkEVMClientMock filename: zk_evm_client.generated.go - IZkEVMClientClientCreator: + IZkEVMClientPool: config: - mockname: ZkEVMClientClientCreatorMock - filename: zk_evm_client_creator.generated.go + mockname: ZkEVMClientCacheMock + filename: zk_evm_client_cache.generated.go diff --git a/aggregator/aggregator.go b/aggregator/aggregator.go new file mode 100644 index 0000000..219f0f3 --- /dev/null +++ b/aggregator/aggregator.go @@ -0,0 +1,12 @@ +package aggregator + +type Aggregator struct { +} + +func New() *Aggregator { + return &Aggregator{} +} + +func (a *Aggregator) Aggregate() { + +} diff --git a/cmd/main.go b/cmd/main.go index 34cfb79..a66967e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -29,6 +29,9 @@ import ( "github.com/0xPolygon/agglayer/interop" "github.com/0xPolygon/agglayer/network" "github.com/0xPolygon/agglayer/rpc" + "github.com/0xPolygon/agglayer/silencer" + "github.com/0xPolygon/agglayer/types" + "github.com/0xPolygon/agglayer/workflow" ) const appName = "cdk-agglayer" @@ -134,6 +137,8 @@ func start(cliCtx *cli.Context) error { ðMan, etm, ) + silencer := silencer.New(c, addr, ðMan, &types.ZkEVMClientCache{}) + workflow := workflow.New(silencer) // Register services server := jRPC.NewServer( @@ -141,7 +146,7 @@ func start(cliCtx *cli.Context) error { []jRPC.Service{ { Name: rpc.INTEROP, - Service: rpc.NewInteropEndpoints(ctx, executor, storage), + Service: rpc.NewInteropEndpoints(ctx, executor, workflow, storage), }, }, ) diff --git a/etherman/etherman.go b/etherman/etherman.go index aae8cb9..c429b16 100644 --- a/etherman/etherman.go +++ b/etherman/etherman.go @@ -68,7 +68,7 @@ func (e *Etherman) BuildTrustedVerifyBatchesTxData( return nil, err } - const pendStateNum uint64 = 0 // TODO hardcoded for now until we implement the pending state feature + const pendStateNum = uint64(0) // TODO hardcoded for now until we implement the pending state feature abi, err := polygonrollupmanager.PolygonrollupmanagerMetaData.GetAbi() if err != nil { log.Errorf("error geting ABI: %v, Proof: %s", err) diff --git a/go.mod b/go.mod index 00ccd9b..58891d7 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( github.com/0xPolygon/cdk-data-availability v0.0.3 github.com/0xPolygonHermez/zkevm-node v0.5.0-RC4 + github.com/cometbft/cometbft v0.38.3 github.com/ethereum/go-ethereum v1.13.8 github.com/gobuffalo/packr/v2 v2.8.3 github.com/jackc/pgconn v1.14.1 @@ -38,7 +39,8 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cosmos/gogoproto v1.4.11 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -64,8 +66,9 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect github.com/google/uuid v1.5.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -96,8 +99,10 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect @@ -108,6 +113,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -133,13 +139,13 @@ require ( go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.17.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.15.0 // indirect diff --git a/go.sum b/go.sum index e8e08a0..9db0457 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/0xPolygonHermez/zkevm-data-streamer v0.1.17/go.mod h1:0QkAXcFa92mFJrC github.com/0xPolygonHermez/zkevm-node v0.5.0-RC4 h1:xQYFDA4+JQ/5PO28n+AC+yz+/Ase2mGPRYbc52i6m/w= github.com/0xPolygonHermez/zkevm-node v0.5.0-RC4/go.mod h1:/+coO2Mg0Zj2NR9XHTB2FVPYT7V7YGx+wXeAidhuFBs= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= @@ -53,6 +53,7 @@ github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMd github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -85,6 +86,8 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= +github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= @@ -123,6 +126,8 @@ github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/cometbft/cometbft v0.38.3 h1:9siuLEzayytYvRdPBhdrV52xcmAgZLj/BNuqTZ9vezg= +github.com/cometbft/cometbft v0.38.3/go.mod h1:kyyCNpl66hAJkiKHJzCYCwrCnZuTWqYDqhP5JPHT4FM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= @@ -136,10 +141,12 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= @@ -165,8 +172,8 @@ github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +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/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5RVoRccG8a5DhOdWdQ4zN62zzo= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= @@ -251,8 +258,9 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -332,8 +340,9 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -566,6 +575,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:FatpGJD2jmJfhZiFDElaC0QhZUDQnxUeAwTGkfAHN3I= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -582,8 +593,8 @@ github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= @@ -593,6 +604,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -625,8 +638,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= +github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -642,6 +655,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -812,8 +827,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -903,8 +918,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1002,15 +1017,15 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/interop/executor.go b/interop/executor.go index 54b1fc8..24b4fa0 100644 --- a/interop/executor.go +++ b/interop/executor.go @@ -2,7 +2,6 @@ package interop import ( "context" - "errors" "fmt" "math/big" @@ -11,28 +10,17 @@ import ( "github.com/0xPolygon/agglayer/types" jRPC "github.com/0xPolygon/cdk-data-availability/rpc" - "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" "github.com/0xPolygonHermez/zkevm-node/log" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/jackc/pgx/v4" ) -var _ types.IZkEVMClientClientCreator = (*zkEVMClientCreator)(nil) - -type zkEVMClientCreator struct{} - -func (zc *zkEVMClientCreator) NewClient(rpc string) types.IZkEVMClient { - return client.NewClient(rpc) -} - type Executor struct { - logger *log.Logger - interopAdminAddr common.Address - config *config.Config - ethTxMan types.IEthTxManager - etherman types.IEtherman - ZkEVMClientCreator types.IZkEVMClientClientCreator + logger *log.Logger + interopAdminAddr common.Address + config *config.Config + ethTxMan types.IEthTxManager + etherman types.IEtherman } func New(logger *log.Logger, cfg *config.Config, @@ -41,120 +29,32 @@ func New(logger *log.Logger, cfg *config.Config, ethTxManager types.IEthTxManager, ) *Executor { return &Executor{ - logger: logger, - interopAdminAddr: interopAdminAddr, - config: cfg, - ethTxMan: ethTxManager, - etherman: etherman, - ZkEVMClientCreator: &zkEVMClientCreator{}, + logger: logger, + interopAdminAddr: interopAdminAddr, + config: cfg, + ethTxMan: ethTxManager, + etherman: etherman, } } const ethTxManOwner = "interop" -func (e *Executor) CheckTx(tx tx.SignedTx) error { - - // Check if the RPC is actually registered, if not it won't be possible to assert soundness (in the future once we are stateless won't be needed) - // TODO: The JSON parsing of the contract is incorrect - if _, ok := e.config.FullNodeRPCs[tx.Tx.RollupID]; !ok { - return fmt.Errorf("there is no RPC registered for %v", tx.Tx.RollupID) - } - - return nil -} - -func (e *Executor) Verify(ctx context.Context, tx tx.SignedTx) error { - err := e.verifyZKP(ctx, tx) - if err != nil { - return fmt.Errorf("failed to verify ZKP: %s", err) - } - - return e.verifySignature(tx) -} - -func (e *Executor) verifyZKP(ctx context.Context, stx tx.SignedTx) error { - // Verify ZKP using eth_call - l1TxData, err := e.etherman.BuildTrustedVerifyBatchesTxData( - uint64(stx.Tx.LastVerifiedBatch), - uint64(stx.Tx.NewVerifiedBatch), - stx.Tx.ZKP, - stx.Tx.RollupID, - ) - if err != nil { - return fmt.Errorf("failed to build verify ZKP tx: %s", err) - } - msg := ethereum.CallMsg{ - From: e.interopAdminAddr, - To: &e.config.L1.RollupManagerContract, - Data: l1TxData, - } - res, err := e.etherman.CallContract(ctx, msg, nil) - if err != nil { - return fmt.Errorf("failed to call verify ZKP response: %s, error: %s", res, err) - } - - return nil -} - -func (e *Executor) verifySignature(stx tx.SignedTx) error { - // Auth: check signature vs admin - signer, err := stx.Signer() - if err != nil { - return errors.New("failed to get signer") - } - - sequencer, err := e.etherman.GetSequencerAddr(stx.Tx.RollupID) - if err != nil { - return errors.New("failed to get admin from L1") - } - if sequencer != signer { - return errors.New("unexpected signer") - } - - return nil -} - -func (e *Executor) Execute(ctx context.Context, signedTx tx.SignedTx) error { - // Check expected root vs root from the managed full node - // TODO: go stateless, depends on https://github.com/0xPolygonHermez/zkevm-prover/issues/581 - // when this happens we should go async from here, since processing all the batches could take a lot of time - zkEVMClient := e.ZkEVMClientCreator.NewClient(e.config.FullNodeRPCs[signedTx.Tx.RollupID]) - batch, err := zkEVMClient.BatchByNumber( - ctx, - big.NewInt(int64(signedTx.Tx.NewVerifiedBatch)), - ) - if err != nil { - return fmt.Errorf("failed to get batch from our node, error: %s", err) - } - if batch.StateRoot != signedTx.Tx.ZKP.NewStateRoot || batch.LocalExitRoot != signedTx.Tx.ZKP.NewLocalExitRoot { - return fmt.Errorf( - "Mismatch detected, expected local exit root: %s actual: %s. expected state root: %s actual: %s", - signedTx.Tx.ZKP.NewLocalExitRoot.Hex(), - batch.LocalExitRoot.Hex(), - signedTx.Tx.ZKP.NewStateRoot.Hex(), - batch.StateRoot.Hex(), - ) - } - - return nil -} - func (e *Executor) Settle(ctx context.Context, signedTx tx.SignedTx, dbTx pgx.Tx) (common.Hash, error) { // Send L1 tx l1TxData, err := e.etherman.BuildTrustedVerifyBatchesTxData( - uint64(signedTx.Tx.LastVerifiedBatch), - uint64(signedTx.Tx.NewVerifiedBatch), - signedTx.Tx.ZKP, - signedTx.Tx.RollupID, + uint64(signedTx.Data.LastVerifiedBatch), + uint64(signedTx.Data.NewVerifiedBatch), + signedTx.Data.ZKP, + signedTx.Data.RollupID, ) if err != nil { - return common.Hash{}, fmt.Errorf("failed to build verify ZKP tx: %s", err) + return common.Hash{}, fmt.Errorf("failed to build ZK proof verification tx data: %w", err) } if err := e.ethTxMan.Add( ctx, ethTxManOwner, - signedTx.Tx.Hash().Hex(), + signedTx.Data.Hash().Hex(), e.interopAdminAddr, &e.config.L1.RollupManagerContract, big.NewInt(0), @@ -162,10 +62,10 @@ func (e *Executor) Settle(ctx context.Context, signedTx tx.SignedTx, dbTx pgx.Tx 0, dbTx, ); err != nil { - return common.Hash{}, fmt.Errorf("failed to add tx to ethTxMan, error: %s", err) + return common.Hash{}, fmt.Errorf("failed to add tx to ethTxMan, error: %w", err) } - log.Debugf("successfuly added tx %s to ethTxMan", signedTx.Tx.Hash().Hex()) - return signedTx.Tx.Hash(), nil + log.Debugf("successfuly added tx %s to ethTxMan", signedTx.Data.Hash().Hex()) + return signedTx.Data.Hash(), nil } func (e *Executor) GetTxStatus(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (result string, err jRPC.Error) { diff --git a/interop/executor_test.go b/interop/executor_test.go index a3354ee..a3bb10e 100644 --- a/interop/executor_test.go +++ b/interop/executor_test.go @@ -9,9 +9,7 @@ import ( jRPC "github.com/0xPolygon/cdk-data-availability/rpc" "github.com/0xPolygonHermez/zkevm-node/ethtxmanager" rpctypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" - "github.com/0xPolygonHermez/zkevm-node/log" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -34,173 +32,6 @@ func TestNewExecutor(t *testing.T) { assert.Equal(t, cfg, executor.config) assert.Equal(t, ethTxManager, executor.ethTxMan) assert.Equal(t, etherman, executor.etherman) - assert.NotNil(t, executor.ZkEVMClientCreator) -} - -func TestExecutor_CheckTx(t *testing.T) { - cfg := &config.Config{ - FullNodeRPCs: map[uint32]string{ - 1: "http://localhost:8545", - }, - } - interopAdminAddr := common.HexToAddress("0x1234567890abcdef") - etherman := mocks.NewEthermanMock(t) - ethTxManager := mocks.NewEthTxManagerMock(t) - - executor := New(log.WithFields("test", "test"), cfg, interopAdminAddr, etherman, ethTxManager) - - // Create a sample signed transaction for testing - signedTx := tx.SignedTx{ - Tx: tx.Tx{ - LastVerifiedBatch: 0, - NewVerifiedBatch: 1, - ZKP: tx.ZKP{ - Proof: []byte("sampleProof"), - }, - RollupID: 1, - }, - } - - err := executor.CheckTx(signedTx) - assert.NoError(t, err) - - signedTx = tx.SignedTx{ - Tx: tx.Tx{ - LastVerifiedBatch: 0, - NewVerifiedBatch: 1, - ZKP: tx.ZKP{ - Proof: []byte("sampleProof"), - }, - RollupID: 0, - }, - } - - err = executor.CheckTx(signedTx) - assert.Error(t, err) -} - -func TestExecutor_VerifyZKP(t *testing.T) { - cfg := &config.Config{} - interopAdminAddr := common.HexToAddress("0x1234567890abcdef") - etherman := mocks.NewEthermanMock(t) - ethTxManager := mocks.NewEthTxManagerMock(t) - tnx := tx.Tx{ - LastVerifiedBatch: 0, - NewVerifiedBatch: 1, - ZKP: tx.ZKP{ - Proof: []byte("sampleProof"), - }, - RollupID: 1, - } - - etherman.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{}, - nil, - ).Once() - - etherman.On( - "CallContract", - mock.Anything, - mock.Anything, - mock.Anything, - ).Return( - []byte{}, - nil, - ).Once() - - executor := New(nil, cfg, interopAdminAddr, etherman, ethTxManager) - - // Create a sample signed transaction for testing - signedTx := tx.SignedTx{ - Tx: tnx, - } - - err := executor.verifyZKP(context.Background(), signedTx) - assert.NoError(t, err) - etherman.AssertExpectations(t) -} - -func TestExecutor_VerifySignature(t *testing.T) { - cfg := &config.Config{} - interopAdminAddr := common.HexToAddress("0x1234567890abcdef") - etherman := mocks.NewEthermanMock(t) - ethTxManager := mocks.NewEthTxManagerMock(t) - - executor := New(nil, cfg, interopAdminAddr, etherman, ethTxManager) - - txn := tx.Tx{ - LastVerifiedBatch: 0, - NewVerifiedBatch: 1, - ZKP: tx.ZKP{ - Proof: []byte("sampleProof"), - }, - RollupID: 1, - } - - pk, err := crypto.GenerateKey() - require.NoError(t, err) - - signedTx, err := txn.Sign(pk) - require.NoError(t, err) - - etherman.On( - "GetSequencerAddr", - uint32(1), - ).Return( - crypto.PubkeyToAddress(pk.PublicKey), - nil, - ).Once() - - err = executor.verifySignature(*signedTx) - require.NoError(t, err) - etherman.AssertExpectations(t) -} - -func TestExecutor_Execute(t *testing.T) { - cfg := &config.Config{} - interopAdminAddr := common.HexToAddress("0x1234567890abcdef") - etherman := mocks.NewEthermanMock(t) - ethTxManager := mocks.NewEthTxManagerMock(t) - - executor := New(log.WithFields("test", "test"), cfg, interopAdminAddr, etherman, ethTxManager) - - // Create a sample signed transaction for testing - signedTx := tx.SignedTx{ - Tx: tx.Tx{ - LastVerifiedBatch: 0, - NewVerifiedBatch: 1, - ZKP: tx.ZKP{ - NewStateRoot: common.BytesToHash([]byte("sampleNewStateRoot")), - Proof: []byte("sampleProof"), - }, - }, - } - - // Mock the ZkEVMClientCreator.NewClient method - mockZkEVMClientCreator := mocks.NewZkEVMClientClientCreatorMock(t) - mockZkEVMClient := mocks.NewZkEVMClientMock(t) - - mockZkEVMClientCreator.On("NewClient", mock.Anything).Return(mockZkEVMClient).Once() - mockZkEVMClient.On("BatchByNumber", mock.Anything, big.NewInt(int64(signedTx.Tx.NewVerifiedBatch))). - Return(&rpctypes.Batch{ - StateRoot: signedTx.Tx.ZKP.NewStateRoot, - LocalExitRoot: signedTx.Tx.ZKP.NewLocalExitRoot, - // Add other necessary fields here - }, nil).Once() - - // Set the ZkEVMClientCreator to return the mock ZkEVMClient - executor.ZkEVMClientCreator = mockZkEVMClientCreator - - err := executor.Execute(context.Background(), signedTx) - require.NoError(t, err) - mockZkEVMClientCreator.AssertExpectations(t) - mockZkEVMClient.AssertExpectations(t) } func TestExecutor_Settle(t *testing.T) { @@ -213,7 +44,7 @@ func TestExecutor_Settle(t *testing.T) { executor := New(nil, cfg, interopAdminAddr, etherman, ethTxManager) signedTx := tx.SignedTx{ - Tx: tx.Tx{ + Data: tx.Tx{ LastVerifiedBatch: 0, NewVerifiedBatch: 1, ZKP: tx.ZKP{ @@ -226,9 +57,9 @@ func TestExecutor_Settle(t *testing.T) { l1TxData := []byte("sampleL1TxData") etherman.On( "BuildTrustedVerifyBatchesTxData", - uint64(signedTx.Tx.LastVerifiedBatch), - uint64(signedTx.Tx.NewVerifiedBatch), - signedTx.Tx.ZKP, + uint64(signedTx.Data.LastVerifiedBatch), + uint64(signedTx.Data.NewVerifiedBatch), + signedTx.Data.ZKP, uint32(1), ).Return( l1TxData, @@ -236,7 +67,7 @@ func TestExecutor_Settle(t *testing.T) { ).Once() ctx := context.Background() - txHash := signedTx.Tx.Hash().Hex() + txHash := signedTx.Data.Hash().Hex() ethTxManager.On( "Add", ctx, ethTxManOwner, @@ -253,7 +84,7 @@ func TestExecutor_Settle(t *testing.T) { hash, err := executor.Settle(ctx, signedTx, dbTx) require.NoError(t, err) - assert.Equal(t, signedTx.Tx.Hash(), hash) + assert.Equal(t, signedTx.Data.Hash(), hash) etherman.AssertExpectations(t) ethTxManager.AssertExpectations(t) diff --git a/mocks/silencer.generated.go b/mocks/silencer.generated.go new file mode 100644 index 0000000..5f84014 --- /dev/null +++ b/mocks/silencer.generated.go @@ -0,0 +1,48 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + tx "github.com/0xPolygon/agglayer/tx" +) + +// SilencerMock is an autogenerated mock type for the ISilencer type +type SilencerMock struct { + mock.Mock +} + +// Silence provides a mock function with given fields: ctx, signedTx +func (_m *SilencerMock) Silence(ctx context.Context, signedTx tx.SignedTx) error { + ret := _m.Called(ctx, signedTx) + + if len(ret) == 0 { + panic("no return value specified for Silence") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, tx.SignedTx) error); ok { + r0 = rf(ctx, signedTx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewSilencerMock creates a new instance of SilencerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSilencerMock(t interface { + mock.TestingT + Cleanup(func()) +}) *SilencerMock { + mock := &SilencerMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/zk_evm_client_creator.generated.go b/mocks/zk_evm_client_pool.generated.go similarity index 82% rename from mocks/zk_evm_client_creator.generated.go rename to mocks/zk_evm_client_pool.generated.go index 98a4675..6c40fa6 100644 --- a/mocks/zk_evm_client_creator.generated.go +++ b/mocks/zk_evm_client_pool.generated.go @@ -7,8 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" ) -// ZkEVMClientClientCreatorMock is an autogenerated mock type for the IZkEVMClientClientCreator type -type ZkEVMClientClientCreatorMock struct { +// ZkEVMClientCacheMock is an autogenerated mock type for the IZkEVMClientClientCreator type +type ZkEVMClientCacheMock struct { mock.Mock } @@ -16,12 +16,12 @@ type ZkEVMClientClientCreatorMock_Expecter struct { mock *mock.Mock } -func (_m *ZkEVMClientClientCreatorMock) EXPECT() *ZkEVMClientClientCreatorMock_Expecter { +func (_m *ZkEVMClientCacheMock) EXPECT() *ZkEVMClientClientCreatorMock_Expecter { return &ZkEVMClientClientCreatorMock_Expecter{mock: &_m.Mock} } -// NewClient provides a mock function with given fields: rpc -func (_m *ZkEVMClientClientCreatorMock) NewClient(rpc string) types.IZkEVMClient { +// GetClient provides a mock function with given fields: rpc +func (_m *ZkEVMClientCacheMock) GetClient(rpc string) types.IZkEVMClient { ret := _m.Called(rpc) if len(ret) == 0 { @@ -73,8 +73,8 @@ func (_c *ZkEVMClientClientCreatorMock_NewClient_Call) RunAndReturn(run func(str func NewZkEVMClientClientCreatorMock(t interface { mock.TestingT Cleanup(func()) -}) *ZkEVMClientClientCreatorMock { - mock := &ZkEVMClientClientCreatorMock{} +}) *ZkEVMClientCacheMock { + mock := &ZkEVMClientCacheMock{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/rpc/rpc.go b/rpc/rpc.go index a9052a6..3f0854d 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -11,6 +11,7 @@ import ( "github.com/0xPolygon/agglayer/interop" "github.com/0xPolygon/agglayer/tx" "github.com/0xPolygon/agglayer/types" + "github.com/0xPolygon/agglayer/workflow" ) // INTEROP is the namespace of the interop service @@ -23,6 +24,7 @@ const ( type InteropEndpoints struct { ctx context.Context executor *interop.Executor + workflow *workflow.Workflow db types.IDB } @@ -30,28 +32,20 @@ type InteropEndpoints struct { func NewInteropEndpoints( ctx context.Context, executor *interop.Executor, + workflow *workflow.Workflow, db types.IDB, ) *InteropEndpoints { return &InteropEndpoints{ ctx: ctx, executor: executor, + workflow: workflow, db: db, } } func (i *InteropEndpoints) SendTx(signedTx tx.SignedTx) (interface{}, jRPC.Error) { - // Check if the RPC is actually registered, if not it won't be possible to assert soundness (in the future once we are stateless won't be needed) - if err := i.executor.CheckTx(signedTx); err != nil { - return "0x0", jRPC.NewRPCError(jRPC.DefaultErrorCode, fmt.Sprintf("there is no RPC registered for %d", signedTx.Tx.RollupID)) - } - - // Verify ZKP using eth_call - if err := i.executor.Verify(i.ctx, signedTx); err != nil { - return "0x0", jRPC.NewRPCError(jRPC.DefaultErrorCode, fmt.Sprintf("failed to verify tx: %s", err)) - } - - if err := i.executor.Execute(i.ctx, signedTx); err != nil { - return "0x0", jRPC.NewRPCError(jRPC.DefaultErrorCode, fmt.Sprintf("failed to execute tx: %s", err)) + if err := i.workflow.Execute(i.ctx, signedTx); err != nil { + return "0x0", jRPC.NewRPCError(jRPC.DefaultErrorCode, err.Error()) } // Send L1 tx @@ -70,9 +64,9 @@ func (i *InteropEndpoints) SendTx(signedTx tx.SignedTx) (interface{}, jRPC.Error if err := dbTx.Commit(i.ctx); err != nil { return "0x0", jRPC.NewRPCError(jRPC.DefaultErrorCode, fmt.Sprintf("failed to commit dbTx, error: %s", err)) } - log.Debugf("successfuly added tx %s to ethTxMan", signedTx.Tx.Hash().Hex()) + log.Debugf("successfuly added tx %s to ethTxMan", signedTx.Data.Hash().Hex()) - return signedTx.Tx.Hash(), nil + return signedTx.Data.Hash(), nil } func (i *InteropEndpoints) GetTxStatus(hash common.Hash) (result interface{}, err jRPC.Error) { diff --git a/rpc/rpc_test.go b/rpc/rpc_test.go index 8652d03..b978a79 100644 --- a/rpc/rpc_test.go +++ b/rpc/rpc_test.go @@ -3,24 +3,22 @@ package rpc import ( "context" "errors" + "fmt" "math/big" "testing" "github.com/0xPolygon/agglayer/config" "github.com/0xPolygon/agglayer/interop" "github.com/0xPolygon/agglayer/mocks" + "github.com/0xPolygon/agglayer/tx" + "github.com/0xPolygon/agglayer/workflow" - agglayerTypes "github.com/0xPolygon/agglayer/rpc/types" "github.com/0xPolygonHermez/zkevm-node/ethtxmanager" - validiumTypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" "github.com/0xPolygonHermez/zkevm-node/log" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - - "github.com/0xPolygon/agglayer/tx" ) func TestInteropEndpointsGetTxStatus(t *testing.T) { @@ -32,14 +30,18 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { dbMock := mocks.NewDBMock(t) dbMock.On("BeginStateTransaction", mock.Anything).Return(nil, errors.New("error")).Once() + interopAdmin := common.HexToAddress("0xadmin") + etherman := mocks.NewEthermanMock(t) + e := interop.New( log.WithFields("module", "test"), &config.Config{}, - common.HexToAddress("0xadmin"), - mocks.NewEthermanMock(t), + interopAdmin, + etherman, mocks.NewEthTxManagerMock(t), ) - i := NewInteropEndpoints(context.Background(), e, dbMock) + w := workflow.New(mocks.NewSilencerMock(t)) + i := NewInteropEndpoints(context.Background(), e, w, dbMock) result, err := i.GetTxStatus(common.HexToHash("0xsomeTxHash")) @@ -64,14 +66,18 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { txManagerMock.On("Result", mock.Anything, ethTxManOwner, txHash.Hex(), txMock). Return(ethtxmanager.MonitoredTxResult{}, errors.New("error")).Once() + interopAdmin := common.HexToAddress("0xadmin") + etherman := mocks.NewEthermanMock(t) + e := interop.New( log.WithFields("module", "test"), &config.Config{}, - common.HexToAddress("0xadmin"), - mocks.NewEthermanMock(t), + interopAdmin, + etherman, txManagerMock, ) - i := NewInteropEndpoints(context.Background(), e, dbMock) + w := workflow.New(mocks.NewSilencerMock(t)) + i := NewInteropEndpoints(context.Background(), e, w, dbMock) result, err := i.GetTxStatus(txHash) @@ -108,14 +114,18 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { txManagerMock.On("Result", mock.Anything, ethTxManOwner, txHash.Hex(), txMock). Return(result, nil).Once() + interopAdmin := common.HexToAddress("0xadmin") + etherman := mocks.NewEthermanMock(t) + e := interop.New( log.WithFields("module", "test"), &config.Config{}, - common.HexToAddress("0xadmin"), - mocks.NewEthermanMock(t), + interopAdmin, + etherman, txManagerMock, ) - i := NewInteropEndpoints(context.Background(), e, dbMock) + w := workflow.New(mocks.NewSilencerMock(t)) + i := NewInteropEndpoints(context.Background(), e, w, dbMock) status, err := i.GetTxStatus(txHash) @@ -128,518 +138,192 @@ func TestInteropEndpointsGetTxStatus(t *testing.T) { }) } -func TestInteropEndpointsSendTx(t *testing.T) { - t.Parallel() - - type testConfig struct { - isL1ContractInMap bool - canBuildZKProof bool - isZKProofValid bool - isTxSigned bool - isAdminRetrieved bool - isSignerValid bool - canGetBatch bool - isBatchValid bool - isDbTxOpen bool - isTxAddedToEthTxMan bool - isTxCommitted bool - - expectedError string +func TestInteropEndpoints_SendTx(t *testing.T) { + interopAdmin := common.HexToAddress("0x2002") + + type testCase struct { + dbMock *mocks.DBMock + ethermanMock *mocks.EthermanMock + silencerMock *mocks.SilencerMock + ethTxManagerMock *mocks.EthTxManagerMock + tx *tx.SignedTx + expectedRes interface{} + expectedErr error } - testFn := func(cfg testConfig) { - fullNodeRPCs := config.FullNodeRPCs{ - 1: "someRPC", - } - tnx := tx.Tx{ - LastVerifiedBatch: agglayerTypes.ArgUint64(1), - NewVerifiedBatch: *agglayerTypes.ArgUint64Ptr(2), - ZKP: tx.ZKP{ - NewStateRoot: common.BigToHash(big.NewInt(11)), - NewLocalExitRoot: common.BigToHash(big.NewInt(11)), - }, - RollupID: 1, - } - signedTx := &tx.SignedTx{Tx: tnx} - ethermanMock := mocks.NewEthermanMock(t) - zkEVMClientCreatorMock := mocks.NewZkEVMClientClientCreatorMock(t) - zkEVMClientMock := mocks.NewZkEVMClientMock(t) - dbMock := mocks.NewDBMock(t) - txMock := new(mocks.TxMock) - ethTxManagerMock := mocks.NewEthTxManagerMock(t) - - executeTestFn := func() { - e := interop.New( - log.WithFields("module", "test"), - &config.Config{ - FullNodeRPCs: fullNodeRPCs, - L1: config.L1Config{RollupManagerContract: common.HexToAddress("0xdeadbeef")}, - }, - common.HexToAddress("0xadmin"), - ethermanMock, - ethTxManagerMock, - ) - i := NewInteropEndpoints(context.Background(), e, dbMock) - i.executor.ZkEVMClientCreator = zkEVMClientCreatorMock - - result, err := i.SendTx(*signedTx) - - if cfg.expectedError != "" { - require.Equal(t, "0x0", result) - require.ErrorContains(t, err, cfg.expectedError) - } else { - require.NoError(t, err) - require.Equal(t, signedTx.Tx.Hash(), result) - } - - ethermanMock.AssertExpectations(t) - zkEVMClientCreatorMock.AssertExpectations(t) - zkEVMClientMock.AssertExpectations(t) - dbMock.AssertExpectations(t) - txMock.AssertExpectations(t) - ethTxManagerMock.AssertExpectations(t) - } - - if !cfg.isL1ContractInMap { - fullNodeRPCs = config.FullNodeRPCs{} - executeTestFn() - - return - } - - if !cfg.canBuildZKProof { - ethermanMock.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{}, - errors.New("error"), - ).Once() - - executeTestFn() - - return - } - - ethermanMock.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{1, 2}, - nil, - ).Once() - - if !cfg.isZKProofValid { - ethermanMock.On( - "CallContract", - mock.Anything, - mock.Anything, - mock.Anything, - ).Return( - []byte{}, - errors.New("error"), - ).Once() - - executeTestFn() - - return + runTest := func(t *testing.T, tc testCase) { + ethTxManagerMock := tc.ethTxManagerMock + if ethTxManagerMock == nil { + ethTxManagerMock = mocks.NewEthTxManagerMock(t) } - ethermanMock.On( - "CallContract", - mock.Anything, - mock.Anything, - mock.Anything, - ).Return( - []byte{1, 2}, - nil, - ).Once() - - if !cfg.isTxSigned { - executeTestFn() - - return - } - - privateKey, err := crypto.GenerateKey() - require.NoError(t, err) - - stx, err := tnx.Sign(privateKey) - require.NoError(t, err) - - signedTx = stx - - if !cfg.isAdminRetrieved { - ethermanMock.On( - "GetSequencerAddr", - uint32(1), - ).Return( - common.Address{}, - errors.New("error"), - ).Once() - - executeTestFn() + e := interop.New( + log.WithFields("module", "test"), + &config.Config{}, + interopAdmin, + tc.ethermanMock, + ethTxManagerMock, + ) + w := workflow.New(tc.silencerMock) + i := NewInteropEndpoints(context.Background(), e, w, tc.dbMock) - return + stx := tc.tx + if tc.tx == nil { + stx = &tx.SignedTx{} } - if !cfg.isSignerValid { - ethermanMock.On( - "GetSequencerAddr", - uint32(1), - ).Return( - common.BytesToAddress([]byte{1, 2, 3, 4}), - nil, - ).Once() - - executeTestFn() - - return + res, err := i.SendTx(*stx) + require.Equal(t, tc.expectedRes, res) + if tc.expectedErr != nil { + require.EqualError(t, err, tc.expectedErr.Error()) + } else { + require.NoError(t, err) } - ethermanMock.On( - "GetSequencerAddr", - uint32(1), - ).Return( - crypto.PubkeyToAddress(privateKey.PublicKey), - nil, - ).Once() - - zkEVMClientCreatorMock.On( - "NewClient", - mock.Anything, - ).Return( - zkEVMClientMock, - ) - - if !cfg.canGetBatch { - zkEVMClientMock.On( - "BatchByNumber", - mock.Anything, - big.NewInt(int64(signedTx.Tx.NewVerifiedBatch)), - ).Return( - nil, - errors.New("error"), - ).Once() + tc.dbMock.AssertExpectations(t) + tc.ethermanMock.AssertExpectations(t) + tc.silencerMock.AssertExpectations(t) + ethTxManagerMock.AssertExpectations(t) + } - executeTestFn() + t.Run("silencer execution failed", func(t *testing.T) { + dbMock := mocks.NewDBMock(t) + expectedErr := errors.New("soundness check failed") - return + ethermanMock := mocks.NewEthermanMock(t) + silencerMock := mocks.NewSilencerMock(t) + silencerMock.On("Silence", mock.Anything, mock.Anything).Return(expectedErr).Once() + + tc := testCase{ + dbMock: dbMock, + ethermanMock: ethermanMock, + silencerMock: silencerMock, + expectedRes: "0x0", + expectedErr: expectedErr, } - if !cfg.isBatchValid { - zkEVMClientMock.On( - "BatchByNumber", - mock.Anything, - big.NewInt(int64(signedTx.Tx.NewVerifiedBatch)), - ).Return( - &validiumTypes.Batch{ - StateRoot: common.BigToHash(big.NewInt(12)), - }, - nil, - ).Once() + runTest(t, tc) + }) - executeTestFn() + t.Run("begin state tx failed", func(t *testing.T) { + dbMock := mocks.NewDBMock(t) + dbMock.On("BeginStateTransaction", mock.Anything).Return(nil, errors.New("failure")).Once() - return + ethermanMock := mocks.NewEthermanMock(t) + silencerMock := mocks.NewSilencerMock(t) + silencerMock.On("Silence", mock.Anything, mock.Anything).Return(nil).Once() + + tc := testCase{ + dbMock: dbMock, + ethermanMock: ethermanMock, + silencerMock: silencerMock, + expectedRes: "0x0", + expectedErr: errors.New("failed to begin dbTx, error: failure"), } - zkEVMClientMock.On( - "BatchByNumber", - mock.Anything, - big.NewInt(int64(signedTx.Tx.NewVerifiedBatch)), - ).Return( - &validiumTypes.Batch{ - StateRoot: common.BigToHash(big.NewInt(11)), - LocalExitRoot: common.BigToHash(big.NewInt(11)), - }, - nil, - ).Once() - - if !cfg.isDbTxOpen { - dbMock.On( - "BeginStateTransaction", - mock.Anything, - ).Return( - nil, - errors.New("error"), - ).Once() + runTest(t, tc) + }) - executeTestFn() + t.Run("settle failed", func(t *testing.T) { + expectedErr := errors.New("ABI encoding is invalid") - return - } + txMock := new(mocks.TxMock) + txMock.On("Rollback", mock.Anything).Return(nil).Once() - dbMock.On( - "BeginStateTransaction", - mock.Anything, - ).Return( - txMock, - nil, - ).Once() - - if !cfg.isTxAddedToEthTxMan { - ethTxManagerMock.On( - "Add", - mock.Anything, - ethTxManOwner, - signedTx.Tx.Hash().Hex(), - mock.Anything, - mock.Anything, - mock.Anything, - mock.Anything, - mock.Anything, - txMock, - ).Return( - errors.New("error"), - ).Once() - - txMock.On( - "Rollback", - mock.Anything, - ).Return( - nil, - ).Once() - - ethermanMock.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{1, 2}, - nil, - ).Once() - - executeTestFn() - - return - } + dbMock := mocks.NewDBMock(t) + dbMock.On("BeginStateTransaction", mock.Anything).Return(txMock, nil).Once() - ethTxManagerMock.On( - "Add", - mock.Anything, - ethTxManOwner, - signedTx.Tx.Hash().Hex(), - mock.Anything, - mock.Anything, - mock.Anything, - mock.Anything, - mock.Anything, - txMock, - ).Return( - nil, - ).Once() - - if !cfg.isTxCommitted { - txMock.On( - "Commit", - mock.Anything, - ).Return( - errors.New("error"), - ).Once() - - ethermanMock.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{1, 2}, - nil, - ).Once() - - executeTestFn() - - return + ethermanMock := mocks.NewEthermanMock(t) + ethermanMock.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, expectedErr).Once() + + silencerMock := mocks.NewSilencerMock(t) + silencerMock.On("Silence", mock.Anything, mock.Anything).Return(nil).Once() + + tc := testCase{ + dbMock: dbMock, + silencerMock: silencerMock, + ethermanMock: ethermanMock, + expectedRes: "0x0", + expectedErr: fmt.Errorf("failed to add tx to ethTxMan, error: failed to build ZK proof verification tx data: %w", expectedErr), } - ethermanMock.On( - "BuildTrustedVerifyBatchesTxData", - uint64(tnx.LastVerifiedBatch), - uint64(tnx.NewVerifiedBatch), - mock.Anything, - uint32(1), - ).Return( - []byte{1, 2}, - nil, - ).Once() - - txMock.On( - "Commit", - mock.Anything, - ).Return( - nil, - ).Once() - - executeTestFn() - } - - t.Run("don't have given contract in map", func(t *testing.T) { - t.Parallel() - - testFn(testConfig{ - isL1ContractInMap: false, - expectedError: "there is no RPC registered", - }) + runTest(t, tc) }) - t.Run("could not build verified ZKP tx data", func(t *testing.T) { - t.Parallel() - - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: false, - expectedError: "failed to build verify ZKP tx", - }) - }) - - t.Run("could not verified ZKP", func(t *testing.T) { - t.Parallel() - - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: false, - expectedError: "failed to call verify ZKP response", - }) - }) + t.Run("db tx commit failed", func(t *testing.T) { + expectedErr := errors.New("commit has failed") - t.Run("could not get signer", func(t *testing.T) { - t.Parallel() + txMock := new(mocks.TxMock) + txMock.On("Commit", mock.Anything).Return(expectedErr).Once() - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: false, - expectedError: "failed to get signer", - }) - }) + dbMock := mocks.NewDBMock(t) + dbMock.On("BeginStateTransaction", mock.Anything).Return(txMock, nil).Once() - t.Run("failed to get admin from L1", func(t *testing.T) { - t.Parallel() + ethermanMock := mocks.NewEthermanMock(t) + ethermanMock.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil).Once() - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: false, - expectedError: "failed to get admin from L1", - }) - }) + silencerMock := mocks.NewSilencerMock(t) + silencerMock.On("Silence", mock.Anything, mock.Anything).Return(nil).Once() - t.Run("unexpected signer", func(t *testing.T) { - t.Parallel() + ethTxManagerMock := mocks.NewEthTxManagerMock(t) + ethTxManagerMock.On("Add", + mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + + tc := testCase{ + dbMock: dbMock, + silencerMock: silencerMock, + ethermanMock: ethermanMock, + ethTxManagerMock: ethTxManagerMock, + expectedRes: "0x0", + expectedErr: fmt.Errorf("failed to commit dbTx, error: %w", expectedErr), + } - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: false, - expectedError: "unexpected signer", - }) + runTest(t, tc) }) - t.Run("error on batch retrieval", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: false, - expectedError: "failed to get batch from our node", - }) - }) + t.Run("send tx successful", func(t *testing.T) { + txMock := new(mocks.TxMock) + txMock.On("Commit", mock.Anything).Return(nil).Once() - t.Run("unexpected batch", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: true, - isBatchValid: false, - expectedError: "Mismatch detected", - }) - }) + dbMock := mocks.NewDBMock(t) + dbMock.On("BeginStateTransaction", mock.Anything).Return(txMock, nil).Once() - t.Run("failed to begin dbTx", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: true, - isBatchValid: true, - isDbTxOpen: false, - expectedError: "failed to begin dbTx", - }) - }) + ethermanMock := mocks.NewEthermanMock(t) + ethermanMock.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil).Once() - t.Run("failed to add tx to ethTxMan", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: true, - isBatchValid: true, - isDbTxOpen: true, - isTxAddedToEthTxMan: false, - expectedError: "failed to add tx to ethTxMan", - }) - }) + silencerMock := mocks.NewSilencerMock(t) + silencerMock.On("Silence", mock.Anything, mock.Anything).Return(nil).Once() - t.Run("failed to commit tx", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: true, - isBatchValid: true, - isDbTxOpen: true, - isTxAddedToEthTxMan: true, - isTxCommitted: false, - expectedError: "failed to commit dbTx", - }) - }) + ethTxManagerMock := mocks.NewEthTxManagerMock(t) + ethTxManagerMock.On("Add", + mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + + signedTx := tx.SignedTx{ + Data: tx.Tx{ + RollupID: uint32(10), + LastVerifiedBatch: 5, + NewVerifiedBatch: 10, + }} + + expectedHash := signedTx.Data.Hash() + + tc := testCase{ + dbMock: dbMock, + silencerMock: silencerMock, + ethermanMock: ethermanMock, + ethTxManagerMock: ethTxManagerMock, + tx: &signedTx, + expectedRes: expectedHash, + expectedErr: nil, + } - t.Run("happy path", func(t *testing.T) { - testFn(testConfig{ - isL1ContractInMap: true, - canBuildZKProof: true, - isZKProofValid: true, - isTxSigned: true, - isAdminRetrieved: true, - isSignerValid: true, - canGetBatch: true, - isBatchValid: true, - isDbTxOpen: true, - isTxAddedToEthTxMan: true, - isTxCommitted: true, - }) + runTest(t, tc) }) } diff --git a/silencer/silencer.go b/silencer/silencer.go new file mode 100644 index 0000000..9adf49e --- /dev/null +++ b/silencer/silencer.go @@ -0,0 +1,138 @@ +package silencer + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + + "github.com/0xPolygon/agglayer/config" + "github.com/0xPolygon/agglayer/tx" + "github.com/0xPolygon/agglayer/types" +) + +type ISilencer interface { + Silence(ctx context.Context, signedTx tx.SignedTx) error +} + +type Silencer struct { + cfg *config.Config + interopAdmin common.Address + etherman types.IEtherman + zkEVMClientsCache types.IZkEVMClientCache +} + +// New returns new instance of Silencer +func New(cfg *config.Config, + interopAdmin common.Address, + etherman types.IEtherman, + zkEVMClientsCache types.IZkEVMClientCache) *Silencer { + return &Silencer{ + cfg: cfg, + interopAdmin: interopAdmin, + etherman: etherman, + zkEVMClientsCache: zkEVMClientsCache, + } +} + +// Silence runs soundness check +func (s *Silencer) Silence(ctx context.Context, signedTx tx.SignedTx) error { + if err := s.verify(ctx, signedTx); err != nil { + return err + } + + // Check expected root vs root from the managed full node + // TODO: go stateless, depends on https://github.com/0xPolygonHermez/zkevm-prover/issues/581 + // when this happens we should go async from here, since processing all the batches could take a lot of time + txData := signedTx.Data + zkEVMClient := s.zkEVMClientsCache.GetClient(s.cfg.FullNodeRPCs[txData.RollupID]) + + batchNumber := new(big.Int).SetUint64(uint64(txData.NewVerifiedBatch)) + batch, err := zkEVMClient.BatchByNumber(ctx, batchNumber) + if err != nil { + return fmt.Errorf("failed to get batch from our node: %w", err) + } + + if batch.StateRoot != txData.ZKP.NewStateRoot { + return fmt.Errorf("mismatch in state roots detected (expected: '%s', actual: '%s')", + batch.StateRoot.Hex(), + txData.ZKP.NewStateRoot.Hex(), + ) + } + + if batch.LocalExitRoot != txData.ZKP.NewLocalExitRoot { + return fmt.Errorf("mismatch in local exit roots detected (expected: '%s', actual: '%s')", + batch.StateRoot.Hex(), + txData.ZKP.NewLocalExitRoot.Hex(), + ) + } + + return nil +} + +// verify performs set of validations against signedTx: +// 1. ZK proof verification +// 2. signature verification +func (s *Silencer) verify(ctx context.Context, stx tx.SignedTx) error { + if _, ok := s.cfg.FullNodeRPCs[stx.Data.RollupID]; !ok { + return fmt.Errorf("there is no RPC registered for rollup %d", stx.Data.RollupID) + } + + if err := s.verifyZKProof(ctx, stx); err != nil { + return err + } + + return s.verifySignature(stx) +} + +// verifyZKProof invokes SC that is accountable for verification of the provided ZK proof +func (s *Silencer) verifyZKProof(ctx context.Context, stx tx.SignedTx) error { + // Verify ZKP using eth_call + l1TxData, err := s.etherman.BuildTrustedVerifyBatchesTxData( + uint64(stx.Data.LastVerifiedBatch), + uint64(stx.Data.NewVerifiedBatch), + stx.Data.ZKP, + stx.Data.RollupID, + ) + if err != nil { + return fmt.Errorf("failed to build ZK proof verification tx data: %w", err) + } + + msg := ethereum.CallMsg{ + From: s.interopAdmin, + To: &s.cfg.L1.RollupManagerContract, + Data: l1TxData, + } + res, err := s.etherman.CallContract(ctx, msg, nil) + if err != nil { + if len(res) > 0 { + return fmt.Errorf("failed to call ZK proof verification (response: %s): %w", res, err) + } + + return fmt.Errorf("failed to call ZK proof verification: %w", err) + } + + return nil +} + +// verifySignature resolves tx signer and compares it against trusted sequencer address +func (s *Silencer) verifySignature(stx tx.SignedTx) error { + signer, err := stx.Signer() + if err != nil { + return fmt.Errorf("failed to resolve signer: %w", err) + } + + trustedSequencer, err := s.etherman.GetSequencerAddr(stx.Data.RollupID) + if err != nil { + return fmt.Errorf("failed to get trusted sequencer address: %w", err) + } + + if trustedSequencer != signer { + return errors.New("unexpected signer") + } + + return nil +} diff --git a/silencer/silencer_test.go b/silencer/silencer_test.go new file mode 100644 index 0000000..9bafcae --- /dev/null +++ b/silencer/silencer_test.go @@ -0,0 +1,332 @@ +package silencer + +import ( + "context" + "errors" + "fmt" + "testing" + + rpctypes "github.com/0xPolygonHermez/zkevm-node/jsonrpc/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/0xPolygon/agglayer/config" + "github.com/0xPolygon/agglayer/mocks" + "github.com/0xPolygon/agglayer/tx" + "github.com/0xPolygon/agglayer/types" +) + +func TestSilencer_New(t *testing.T) { + cfg := &config.Config{FullNodeRPCs: map[uint32]string{3: "http://localhost:8545"}} + interopAdmin := common.HexToAddress("0x1234567890abcdef") + etherman := mocks.NewEthermanMock(t) + clientCreator := mocks.NewZkEVMClientClientCreatorMock(t) + + executor := New(cfg, interopAdmin, etherman, clientCreator) + + require.NotNil(t, executor) + require.Equal(t, interopAdmin, executor.interopAdmin) + require.Equal(t, cfg, executor.cfg) + require.Equal(t, etherman, executor.etherman) + require.Equal(t, clientCreator, executor.zkEVMClientsCache) + +} + +func TestSilencer_Silence(t *testing.T) { + tests := []struct { + name string + txStateRoot common.Hash + txLocalExitRoot common.Hash + batchStateRoot common.Hash + batchLocalExitRoot common.Hash + clientErr error + expectedErrMsg string + }{ + { + name: "happy path", + txStateRoot: common.BytesToHash([]byte("sampleNewStateRoot")), + txLocalExitRoot: common.BytesToHash([]byte("sampleExitRoot")), + clientErr: nil, + expectedErrMsg: "", + }, + { + name: "failed to retrieve batch", + txStateRoot: common.BytesToHash([]byte("sampleNewStateRoot")), + txLocalExitRoot: common.BytesToHash([]byte("sampleExitRoot")), + clientErr: errors.New("timeout"), + expectedErrMsg: "failed to get batch from our node: timeout", + }, + { + name: "state roots mismatch", + txStateRoot: common.BytesToHash([]byte("txStateRoot")), + txLocalExitRoot: common.BytesToHash([]byte("txExitRoot")), + batchStateRoot: common.BytesToHash([]byte("batchStateRoot")), + batchLocalExitRoot: common.BytesToHash([]byte("batchExitRoot")), + clientErr: nil, + expectedErrMsg: "mismatch in state roots detected", + }, + { + name: "local exit roots mismatch", + txStateRoot: common.BytesToHash([]byte("stateRoot")), + txLocalExitRoot: common.BytesToHash([]byte("txExitRoot")), + batchStateRoot: common.BytesToHash([]byte("stateRoot")), + batchLocalExitRoot: common.BytesToHash([]byte("batchExitRoot")), + clientErr: nil, + expectedErrMsg: "mismatch in local exit roots detected", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + const rollupID = uint32(10) + + cfg := &config.Config{FullNodeRPCs: map[uint32]string{rollupID: "http://localhost:10000"}} + interopAdminAddr := common.HexToAddress("0x1001") + + createMockEtherman := func(sequencerAddr common.Address) *mocks.EthermanMock { + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On("CallContract", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On( + "GetSequencerAddr", + mock.Anything, + ).Return( + sequencerAddr, + nil, + ).Once() + + return etherman + } + + setupMockZkEVMClient := func(batchStateRoot, batchLocalExitRoot common.Hash, err error) ( + *mocks.ZkEVMClientCacheMock, + *mocks.ZkEVMClientMock) { + clientMock := mocks.NewZkEVMClientMock(t) + if err == nil { + batch := &rpctypes.Batch{ + StateRoot: batchStateRoot, + LocalExitRoot: batchLocalExitRoot, + } + clientMock.On("BatchByNumber", mock.Anything, mock.Anything). + Return(batch, nil).Once() + } else { + clientMock.On("BatchByNumber", mock.Anything, mock.Anything). + Return(nil, err).Once() + } + + clientCreatorMock := mocks.NewZkEVMClientClientCreatorMock(t) + clientCreatorMock.On("GetClient", mock.Anything). + Return(clientMock).Once() + + return clientCreatorMock, clientMock + } + + tx := tx.Tx{ + LastVerifiedBatch: 1, + NewVerifiedBatch: 2, + RollupID: rollupID, + ZKP: tx.ZKP{ + NewStateRoot: tt.txStateRoot, + NewLocalExitRoot: tt.txLocalExitRoot, + }, + } + + sequencerKey, err := crypto.GenerateKey() + require.NoError(t, err) + + signedTx, err := tx.Sign(sequencerKey) + require.NoError(t, err) + + etherman := createMockEtherman(crypto.PubkeyToAddress(sequencerKey.PublicKey)) + batchStateRoot := tx.ZKP.NewStateRoot + batchLocalExitRoot := tx.ZKP.NewLocalExitRoot + if (tt.batchStateRoot != common.Hash{}) { + batchStateRoot = tt.batchStateRoot + } + if (tt.batchLocalExitRoot != common.Hash{}) { + batchLocalExitRoot = tt.batchLocalExitRoot + } + clientCreatorMock, clientMock := setupMockZkEVMClient(batchStateRoot, batchLocalExitRoot, tt.clientErr) + + silencer := New(cfg, interopAdminAddr, etherman, clientCreatorMock) + err = silencer.Silence(context.Background(), *signedTx) + + if tt.expectedErrMsg != "" { + require.ErrorContains(t, err, tt.expectedErrMsg) + } else { + require.NoError(t, err) + } + + clientCreatorMock.AssertExpectations(t) + clientMock.AssertExpectations(t) + }) + } +} + +func TestSilencer_verify(t *testing.T) { + createSilencer := func(cfg *config.Config, etherman types.IEtherman) *Silencer { + interopAdmin := common.HexToAddress("0x100") + return New(cfg, interopAdmin, etherman, mocks.NewZkEVMClientClientCreatorMock(t)) + } + + defaultRollupID := uint32(2) + defaultCfg := &config.Config{FullNodeRPCs: map[uint32]string{ + defaultRollupID: "http://localhost:8545", + }} + + t.Run("no full node RPC registered for the given rollup", func(t *testing.T) { + stx := tx.SignedTx{Data: tx.Tx{RollupID: 20}} + + s := createSilencer(defaultCfg, nil) + err := s.verify(context.Background(), stx) + require.ErrorContains(t, err, fmt.Sprintf("there is no RPC registered for rollup %d", stx.Data.RollupID)) + }) + + t.Run("ZK proof verification failure", func(t *testing.T) { + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, errors.New("error")).Once() + + s := createSilencer(defaultCfg, etherman) + stx := tx.SignedTx{Data: tx.Tx{RollupID: defaultRollupID}} + err := s.verify(context.Background(), stx) + require.ErrorContains(t, err, "failed to build ZK proof verification tx data: error") + + etherman.AssertExpectations(t) + }) + + t.Run("ZK proof verification failure", func(t *testing.T) { + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On("CallContract", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte("Hello world!"), errors.New("failure")).Once() + + s := createSilencer(defaultCfg, etherman) + stx := tx.SignedTx{Data: tx.Tx{RollupID: defaultRollupID}} + err := s.verify(context.Background(), stx) + require.ErrorContains(t, err, "failed to call ZK proof verification (response: Hello world!): failure") + + etherman.AssertExpectations(t) + }) + + t.Run("signature verification failure (no signature)", func(t *testing.T) { + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On("CallContract", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + s := createSilencer(defaultCfg, etherman) + stx := tx.SignedTx{Data: tx.Tx{RollupID: defaultRollupID}} + err := s.verify(context.Background(), stx) + require.ErrorContains(t, err, "failed to resolve signer: invalid signature length") + }) + + t.Run("signature verification failure (failed to retrieve sequencer addr)", func(t *testing.T) { + getSequencerAddrErr := errors.New("execution failed") + + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On("CallContract", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On( + "GetSequencerAddr", + mock.Anything, + ).Return( + common.Address{}, + getSequencerAddrErr, + ).Once() + + s := createSilencer(defaultCfg, etherman) + txData := tx.Tx{RollupID: defaultRollupID} + + pk, err := crypto.GenerateKey() + require.NoError(t, err) + + signedTx, err := txData.Sign(pk) + require.NoError(t, err) + + err = s.verify(context.Background(), *signedTx) + require.ErrorContains(t, err, fmt.Sprintf("failed to get trusted sequencer address: %s", getSequencerAddrErr.Error())) + }) + + t.Run("signature verification failure (sequencer is not the tx signer)", func(t *testing.T) { + etherman := mocks.NewEthermanMock(t) + etherman.On("BuildTrustedVerifyBatchesTxData", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On("CallContract", + mock.Anything, + mock.Anything, + mock.Anything, + ).Return([]byte{}, nil).Once() + + etherman.On( + "GetSequencerAddr", + mock.Anything, + ).Return( + common.HexToAddress("0x12345"), + nil, + ).Once() + + s := createSilencer(defaultCfg, etherman) + txData := tx.Tx{RollupID: defaultRollupID} + + pk, err := crypto.GenerateKey() + require.NoError(t, err) + + signedTx, err := txData.Sign(pk) + require.NoError(t, err) + + err = s.verify(context.Background(), *signedTx) + require.ErrorContains(t, err, "unexpected signer") + }) +} diff --git a/tx/tx.go b/tx/tx.go index 07511f5..8b319a5 100644 --- a/tx/tx.go +++ b/tx/tx.go @@ -2,9 +2,11 @@ package tx import ( "crypto/ecdsa" - "github.com/0xPolygon/agglayer/rpc/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + "github.com/0xPolygon/agglayer/rpc/types" ) // type L1Consensus string @@ -48,19 +50,19 @@ func (t *Tx) Sign(privateKey *ecdsa.PrivateKey) (*SignedTx, error) { return nil, err } return &SignedTx{ - Tx: *t, + Data: *t, Signature: sig, }, nil } type SignedTx struct { - Tx Tx `json:"tx"` + Data Tx `json:"tx"` Signature types.ArgBytes `json:"signature"` } // Signer returns the address of the signer func (s *SignedTx) Signer() (common.Address, error) { - pubKey, err := crypto.SigToPub(s.Tx.Hash().Bytes(), s.Signature) + pubKey, err := crypto.SigToPub(s.Data.Hash().Bytes(), s.Signature) if err != nil { return common.Address{}, err } diff --git a/types/interfaces.go b/types/interfaces.go index ac5d678..2babb78 100644 --- a/types/interfaces.go +++ b/types/interfaces.go @@ -33,6 +33,6 @@ type IZkEVMClient interface { BatchByNumber(ctx context.Context, number *big.Int) (*types.Batch, error) } -type IZkEVMClientClientCreator interface { - NewClient(rpc string) IZkEVMClient +type IZkEVMClientCache interface { + GetClient(rpc string) IZkEVMClient } diff --git a/types/zk_evm_client_cache.go b/types/zk_evm_client_cache.go new file mode 100644 index 0000000..a9a90b0 --- /dev/null +++ b/types/zk_evm_client_cache.go @@ -0,0 +1,23 @@ +package types + +import "github.com/0xPolygonHermez/zkevm-node/jsonrpc/client" + +var _ IZkEVMClientCache = (*ZkEVMClientCache)(nil) + +type ZkEVMClientCache struct { + clients map[string]IZkEVMClient +} + +func New() *ZkEVMClientCache { + return &ZkEVMClientCache{clients: map[string]IZkEVMClient{}} +} + +func (zc *ZkEVMClientCache) GetClient(rpc string) IZkEVMClient { + c, ok := zc.clients[rpc] + if !ok { + c = client.NewClient(rpc) + zc.clients[rpc] = c + } + + return c +} diff --git a/workflow/workflow.go b/workflow/workflow.go new file mode 100644 index 0000000..5c53288 --- /dev/null +++ b/workflow/workflow.go @@ -0,0 +1,102 @@ +package workflow + +import ( + "context" + + abciTypes "github.com/cometbft/cometbft/abci/types" + + "github.com/0xPolygon/agglayer/silencer" + "github.com/0xPolygon/agglayer/tx" +) + +var _ abciTypes.Application = (*Workflow)(nil) + +type Workflow struct { + silencer silencer.ISilencer + // sequencer *sequencer.Sequencer + // aggregator *aggregator.Aggregator +} + +func New(silencer silencer.ISilencer) *Workflow { + return &Workflow{ + silencer: silencer, + } +} + +func (w *Workflow) Execute(ctx context.Context, stx tx.SignedTx) error { + if err := w.silencer.Silence(ctx, stx); err != nil { + return err + } + + // TODO: Add missing parts here + //nolint:godox + return nil +} + +// Info/Query Connection +// Return application info +func (w *Workflow) Info(_ context.Context, _ *abciTypes.RequestInfo) (*abciTypes.ResponseInfo, error) { + panic("not implemented") // TODO: Implement +} + +func (w *Workflow) Query(_ context.Context, _ *abciTypes.RequestQuery) (*abciTypes.ResponseQuery, error) { + panic("not implemented") // TODO: Implement +} + +// Mempool Connection +// Validate a tx for the mempool +func (w *Workflow) CheckTx(_ context.Context, _ *abciTypes.RequestCheckTx) (*abciTypes.ResponseCheckTx, error) { + panic("not implemented") // TODO: It should do the soundness check +} + +// Consensus Connection +// Initialize blockchain w validators/other info from CometBFT +func (w *Workflow) InitChain(_ context.Context, _ *abciTypes.RequestInitChain) (*abciTypes.ResponseInitChain, error) { + panic("not implemented") // TODO: Implement +} + +func (w *Workflow) PrepareProposal(_ context.Context, _ *abciTypes.RequestPrepareProposal) (*abciTypes.ResponsePrepareProposal, error) { + panic("not implemented") // TODO: It should do the aggregation and ordering/sequencing +} + +func (w *Workflow) ProcessProposal(_ context.Context, _ *abciTypes.RequestProcessProposal) (*abciTypes.ResponseProcessProposal, error) { + panic("not implemented") // TODO: It should do the verification of the final proof and perform the soundness check +} + +// Deliver the decided block with its txs to the Application +func (w *Workflow) FinalizeBlock(_ context.Context, _ *abciTypes.RequestFinalizeBlock) (*abciTypes.ResponseFinalizeBlock, error) { + panic("not implemented") // TODO: Implement +} + +// Create application specific vote extension +func (w *Workflow) ExtendVote(_ context.Context, _ *abciTypes.RequestExtendVote) (*abciTypes.ResponseExtendVote, error) { + panic("not implemented") // TODO: Implement +} + +// Verify application's vote extension data +func (w *Workflow) VerifyVoteExtension(_ context.Context, _ *abciTypes.RequestVerifyVoteExtension) (*abciTypes.ResponseVerifyVoteExtension, error) { + panic("not implemented") // TODO: Implement +} + +// Commit the state and return the application Merkle root hash +func (w *Workflow) Commit(_ context.Context, _ *abciTypes.RequestCommit) (*abciTypes.ResponseCommit, error) { + panic("not implemented") // TODO: Implement +} + +// State Sync Connection +// List available snapshots +func (w *Workflow) ListSnapshots(_ context.Context, _ *abciTypes.RequestListSnapshots) (*abciTypes.ResponseListSnapshots, error) { + panic("not implemented") // TODO: Implement +} + +func (w *Workflow) OfferSnapshot(_ context.Context, _ *abciTypes.RequestOfferSnapshot) (*abciTypes.ResponseOfferSnapshot, error) { + panic("not implemented") // TODO: Implement +} + +func (w *Workflow) LoadSnapshotChunk(_ context.Context, _ *abciTypes.RequestLoadSnapshotChunk) (*abciTypes.ResponseLoadSnapshotChunk, error) { + panic("not implemented") // TODO: Implement +} + +func (w *Workflow) ApplySnapshotChunk(_ context.Context, _ *abciTypes.RequestApplySnapshotChunk) (*abciTypes.ResponseApplySnapshotChunk, error) { + panic("not implemented") // TODO: Implement +}