diff --git a/bindings/megapool/beacon-state-verifier.go b/bindings/megapool/beacon-state-verifier.go index 00f314def..4cdbe6a57 100644 --- a/bindings/megapool/beacon-state-verifier.go +++ b/bindings/megapool/beacon-state-verifier.go @@ -53,3 +53,11 @@ func getBeaconStateVerifier(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*ro defer BeaconStateVerifierLock.Unlock() return rp.GetContract("beaconStateVerifier", opts) } + +func GetBeaconStateVerifierVersion(rp *rocketpool.RocketPool, opts *bind.CallOpts) (uint8, error) { + beaconStateVerifier, err := getBeaconStateVerifier(rp, opts) + if err != nil { + return 0, err + } + return rocketpool.GetContractVersion(rp, *beaconStateVerifier.Address, opts) +} diff --git a/bindings/utils/state/contracts.go b/bindings/utils/state/contracts.go index 9c2b693e8..3ba6f2ce1 100644 --- a/bindings/utils/state/contracts.go +++ b/bindings/utils/state/contracts.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/hashicorp/go-version" - "github.com/rocket-pool/smartnode/bindings/deposit" "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/bindings/utils/multicall" ) @@ -233,52 +232,5 @@ func NewNetworkContracts(rp *rocketpool.RocketPool, multicallerAddress common.Ad *wrappers[i].contract = contract } - err = contracts.getCurrentVersion(rp) - if err != nil { - return nil, fmt.Errorf("error getting network contract version: %w", err) - } - return contracts, nil } - -// Get the current version of the network -func (c *NetworkContracts) getCurrentVersion(rp *rocketpool.RocketPool) error { - opts := &bind.CallOpts{ - BlockNumber: c.ElBlockNumber, - } - - depositPoolVersion, err := deposit.GetRocketDepositPoolVersion(rp, opts) - if err != nil { - return fmt.Errorf("error checking deposit pool version: %w", err) - } - - // Check for v1.4 (Saturn 1) - if depositPoolVersion > 3 { - c.Version, err = version.NewSemver("1.4.0") - return err - } - - // Check for v1.2 - nodeStakingVersion, err := rocketpool.GetContractVersion(rp, *c.RocketNodeStaking.Address, opts) - if err != nil { - return fmt.Errorf("error checking node staking version: %w", err) - } - if nodeStakingVersion > 3 { - c.Version, err = version.NewSemver("1.2.0") - return err - } - - // Check for v1.1 - nodeMgrVersion, err := rocketpool.GetContractVersion(rp, *c.RocketNodeManager.Address, opts) - if err != nil { - return fmt.Errorf("error checking node manager version: %w", err) - } - if nodeMgrVersion > 1 { - c.Version, err = version.NewSemver("1.1.0") - return err - } - - // v1.0 - c.Version, err = version.NewSemver("1.0.0") - return err -} diff --git a/bindings/utils/version-checker.go b/bindings/utils/version-checker.go index 9a4418791..cfa87ec2b 100644 --- a/bindings/utils/version-checker.go +++ b/bindings/utils/version-checker.go @@ -7,12 +7,21 @@ import ( "github.com/hashicorp/go-version" "github.com/rocket-pool/smartnode/bindings/deposit" + "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/network" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/rocketpool" ) func GetCurrentVersion(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*version.Version, error) { + beaconStateVerifierVersion, err := megapool.GetBeaconStateVerifierVersion(rp, opts) + if err != nil { + return nil, fmt.Errorf("error checking beacon state verifier version: %w", err) + } + if beaconStateVerifierVersion == 2 { + return version.NewSemver("1.4.1") + } + depositPoolVersion, err := deposit.GetRocketDepositPoolVersion(rp, opts) if err != nil { return nil, fmt.Errorf("error checking deposit pool version: %w", err) @@ -20,6 +29,7 @@ func GetCurrentVersion(rp *rocketpool.RocketPool, opts *bind.CallOpts) (*version // Check for v1.4 (Saturn 1) if depositPoolVersion > 3 { + return version.NewSemver("1.4.0") } diff --git a/go.mod b/go.mod index b3a9f41d6..1efcb2b3a 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/docker/docker v28.5.2+incompatible github.com/dustin/go-humanize v1.0.1 - github.com/ethereum/go-ethereum v1.17.0 + github.com/ethereum/go-ethereum v1.17.4 github.com/fatih/color v1.16.0 github.com/felixge/fgprof v0.9.5 github.com/ferranbt/fastssz v0.1.4 @@ -74,7 +74,7 @@ require ( github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect - github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/cyphar/filepath-securejoin v0.6.1 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect @@ -83,8 +83,9 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/dot v1.6.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fjl/jsonw v0.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gdamore/encoding v1.0.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -166,7 +167,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.3.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect diff --git a/go.sum b/go.sum index d3a9b9da8..59bde4127 100644 --- a/go.sum +++ b/go.sum @@ -170,8 +170,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= -github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= -github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc= +github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= @@ -222,12 +222,12 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= -github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls= +github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= -github.com/ethereum/go-ethereum v1.17.0 h1:2D+1Fe23CwZ5tQoAS5DfwKFNI1HGcTwi65/kRlAVxes= -github.com/ethereum/go-ethereum v1.17.0/go.mod h1:2W3msvdosS/MCWytpqTcqgFiRYbTH59FxDJzqah120o= +github.com/ethereum/go-ethereum v1.17.4 h1:uA4q+qiLp7QImBsjdRbINu8iX6OEVmj4DPc5/E5Fsxc= +github.com/ethereum/go-ethereum v1.17.4/go.mod h1:qMdgwqqRAen+aT8P7KKQKi0Qt6RzG4cfejVAbCpJgqA= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -240,6 +240,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/fjl/jsonw v0.1.0 h1:V3MyR79fjLpn/+bMgvegdGUIhoJOzjmqWcKDgcOmY1I= +github.com/fjl/jsonw v0.1.0/go.mod h1:2KMLevM6FXEJnfhtk7naXu9vZdVfOma1GlnGdPRlumU= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= @@ -751,12 +753,14 @@ github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSN github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= +github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= github.com/pion/ice/v2 v2.3.34 h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM= github.com/pion/ice/v2 v2.3.34/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= github.com/pion/interceptor v0.1.30 h1:au5rlVHsgmxNi+v/mjOPazbW1SHzfx7/hYOEYQnUcxA= github.com/pion/interceptor v0.1.30/go.mod h1:RQuKT5HTdkP2Fi0cuOS5G5WNymTjzXaGF75J4k7z2nc= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= @@ -773,12 +777,12 @@ github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= -github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= -github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/stun/v3 v3.1.2 h1:86IhD8wFn6IDW4b1/0QzoQS+f5PeA8OHHRn8UZW5ErY= +github.com/pion/stun/v3 v3.1.2/go.mod h1:H7gDic7nNwlUL05pbs6T1dtaBehh/KjupxfWw3ZI7cA= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= -github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= +github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/webrtc/v3 v3.3.0 h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I= @@ -901,8 +905,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= -github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= +github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= @@ -950,8 +954,8 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZA github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= -github.com/wlynxg/anet v0.0.4 h1:0de1OFQxnNqAu+x2FAKKCVIrnfGKQbs7FQz++tB0+Uw= -github.com/wlynxg/anet v0.0.4/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -1253,8 +1257,8 @@ golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/rocketpool-cli/megapool/exit-validator.go b/rocketpool-cli/megapool/exit-validator.go index 1eb0ccee1..0dcc05857 100644 --- a/rocketpool-cli/megapool/exit-validator.go +++ b/rocketpool-cli/megapool/exit-validator.go @@ -135,10 +135,16 @@ func getExitableValidator(fetchExitQueueEstimate bool) (uint64, bool, error) { activeValidators := []api.MegapoolValidatorDetails{} exitingValidators := []api.MegapoolValidatorDetails{} + // Voluntary exits require activation_epoch + SHARD_COMMITTEE_PERIOD. + shardCommitteePeriod := status.ShardCommitteePeriod + if shardCommitteePeriod == 0 { + shardCommitteePeriod = 256 + } + for _, validator := range status.Megapool.Validators { if validator.Activated && !validator.Exiting && !validator.Exited && validator.BeaconStatus.Status != beacon.ValidatorState_ActiveExiting { // Check if validator is old enough to exit - earliestExitEpoch := validator.BeaconStatus.ActivationEpoch + 256 + earliestExitEpoch := validator.BeaconStatus.ActivationEpoch + shardCommitteePeriod if status.BeaconHead.Epoch >= earliestExitEpoch { activeValidators = append(activeValidators, validator) } diff --git a/rocketpool-cli/megapool/notify-validator-exit.go b/rocketpool-cli/megapool/notify-validator-exit.go index cb32571d3..fa2910f3a 100644 --- a/rocketpool-cli/megapool/notify-validator-exit.go +++ b/rocketpool-cli/megapool/notify-validator-exit.go @@ -21,7 +21,7 @@ func getExitedValidator() (uint64, bool, error) { return 0, false, err } defer rp.Close() - // Get Megapool status + fmt.Println("Loading megapool validators at the finalized beacon state...") status, err := rp.MegapoolStatus(true) if err != nil { return 0, false, err @@ -30,22 +30,38 @@ func getExitedValidator() (uint64, bool, error) { activeValidators := []api.MegapoolValidatorDetails{} for _, validator := range status.Megapool.Validators { - if validator.Activated && !validator.Exiting && !validator.Exited && validator.BeaconStatus.WithdrawableEpoch != FarFutureEpoch { - activeValidators = append(activeValidators, validator) + if !validator.Activated || validator.Exiting || validator.Exited { + continue } + if !validator.BeaconStatus.Exists { + continue + } + if validator.BeaconStatus.ExitEpoch == FarFutureEpoch { + continue + } + if validator.BeaconStatus.WithdrawableEpoch == FarFutureEpoch { + continue + } + activeValidators = append(activeValidators, validator) } if len(activeValidators) > 0 { sort.Sort(ByIndex(activeValidators)) options := make([]string, len(activeValidators)) for vi, v := range activeValidators { - options[vi] = fmt.Sprintf("ID: %d - Index: %d - Pubkey: 0x%s", v.ValidatorId, v.ValidatorIndex, v.PubKey.String()) + options[vi] = fmt.Sprintf( + "ID: %d - Index: %d - exit_epoch: %d - withdrawable_epoch: %d - Pubkey: 0x%s", + v.ValidatorId, v.ValidatorIndex, + v.BeaconStatus.ExitEpoch, v.BeaconStatus.WithdrawableEpoch, + v.PubKey.String(), + ) } selected, _ := prompt.Select("Please select a validator to notify the exit:", options) // Get validators return uint64(activeValidators[selected].ValidatorId), true, nil } - fmt.Println("Can't notify the exit of any validators") + fmt.Println("No validators are ready to notify exit.") + fmt.Println("A validator is only listed once its exit_epoch is set on the *finalized* beacon state") return 0, false, nil } @@ -58,13 +74,28 @@ func notifyValidatorExit(validatorId uint64, yes bool) error { } defer rp.Close() + fmt.Printf("Checking whether validator id %d can be notified...\n", validatorId) + response, err := rp.CanNotifyValidatorExit(validatorId) if err != nil { - return err + return fmt.Errorf("could not check notify-validator-exit for id %d: %w", validatorId, err) } if !response.CanExit { - return nil + fmt.Printf("Cannot notify the exit of validator id %d.\n", validatorId) + if response.InvalidStatus { + fmt.Println(" The validator is not in a staked state.") + } + if response.AlreadyExiting { + fmt.Println(" Exit has already been notified for this validator.") + } + if response.AlreadyExited { + fmt.Println(" The validator has already been fully exited on the megapool.") + } + if response.ExitNotFinalized { + fmt.Println(" The validator exit is not yet reflected in the finalized beacon state.") + } + return fmt.Errorf("cannot notify exit of validator id %d", validatorId) } // Assign max fees @@ -79,10 +110,12 @@ func notifyValidatorExit(validatorId uint64, yes bool) error { return nil } + fmt.Printf("Submitting notify-exit for validator id %d ...\n", validatorId) + // Exit the validator resp, err := rp.NotifyValidatorExit(validatorId) if err != nil { - return err + return fmt.Errorf("notify-validator-exit failed for id %d: %w", validatorId, err) } fmt.Printf("Notifying validator exit...\n") diff --git a/rocketpool/api/megapool/distribute.go b/rocketpool/api/megapool/distribute.go index 947fad2e4..8acdac286 100644 --- a/rocketpool/api/megapool/distribute.go +++ b/rocketpool/api/megapool/distribute.go @@ -43,7 +43,7 @@ func canDistributeMegapool(c *cli.Command) (*api.CanDistributeMegapoolResponse, } // Load the megapool details - details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil) + details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil, false) if err != nil { return nil, err } diff --git a/rocketpool/api/megapool/latest-block-withdrawals.go b/rocketpool/api/megapool/latest-block-withdrawals.go index d953569ba..1b8fec6d6 100644 --- a/rocketpool/api/megapool/latest-block-withdrawals.go +++ b/rocketpool/api/megapool/latest-block-withdrawals.go @@ -1,6 +1,7 @@ package megapool import ( + "context" "fmt" "github.com/urfave/cli/v3" @@ -22,6 +23,10 @@ func getLatestBlockWithdrawals(c *cli.Command) (*api.LatestBlockWithdrawalsRespo if err != nil { return nil, err } + ec, err := services.GetEthClient(c) + if err != nil { + return nil, err + } blockToRequest := "head" const maxAttempts = 8 @@ -51,9 +56,15 @@ func getLatestBlockWithdrawals(c *cli.Command) (*api.LatestBlockWithdrawalsRespo blockToRequest = fmt.Sprintf("%d", nextSlot) } + // Gloas blocks only commit to the EL block hash, so the number has to be resolved + elBlockNumber, _, err := beacon.ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + return nil, err + } + response := &api.LatestBlockWithdrawalsResponse{ Slot: block.Slot, - BlockNumber: block.ExecutionBlockNumber, + BlockNumber: elBlockNumber, Withdrawals: block.Withdrawals, } return response, nil diff --git a/rocketpool/api/megapool/notify-validator-exit.go b/rocketpool/api/megapool/notify-validator-exit.go index d7e885f49..99a2433d5 100644 --- a/rocketpool/api/megapool/notify-validator-exit.go +++ b/rocketpool/api/megapool/notify-validator-exit.go @@ -1,15 +1,47 @@ package megapool import ( + "errors" + "fmt" + "strconv" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/types" "github.com/rocket-pool/smartnode/shared/services" + "github.com/rocket-pool/smartnode/shared/services/beacon" "github.com/rocket-pool/smartnode/shared/types/api" + "github.com/rocket-pool/smartnode/shared/types/eth2" ) +var errExitNotFinalized = errors.New("validator exit not yet finalized") + +func ensureExitFinalized(bc beacon.Client, pubkey types.ValidatorPubkey) (eth2.BeaconState, error) { + beaconState, err := services.GetBeaconState(bc) + if err != nil { + return nil, err + } + validators := beaconState.GetValidators() + + validatorIndexStr, err := bc.GetValidatorIndex(pubkey) + if err != nil { + return nil, fmt.Errorf("error getting beacon index: %w", err) + } + validatorIndex, err := strconv.ParseUint(validatorIndexStr, 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing beacon index %q: %w", validatorIndexStr, err) + } + if validatorIndex >= uint64(len(validators)) { + return nil, fmt.Errorf("%w: validator (beacon index %d) is not yet included in the finalized beacon state", errExitNotFinalized, validatorIndex) + } + if validators[validatorIndex].WithdrawableEpoch >= farFutureEpoch { + return nil, fmt.Errorf("%w: validator (beacon index %d) withdrawable_epoch is still FAR_FUTURE on finalized state", errExitNotFinalized, validatorIndex) + } + return beaconState, nil +} + func canNotifyValidatorExit(c *cli.Command, validatorId uint32) (*api.CanNotifyValidatorExitResponse, error) { // Get services @@ -55,9 +87,33 @@ func canNotifyValidatorExit(c *cli.Command, validatorId uint32) (*api.CanNotifyV return nil, err } - // Check validator status if !validatorInfo.Staked { response.InvalidStatus = true + response.CanExit = false + return &response, nil + } + if validatorInfo.Exited { + response.AlreadyExited = true + response.CanExit = false + return &response, nil + } + if validatorInfo.Exiting { + response.AlreadyExiting = true + response.CanExit = false + return &response, nil + } + + pubkey := types.ValidatorPubkey(validatorInfo.Pubkey) + + // Proofs use finalized state — do not build/submit until the exit is there. + beaconState, err := ensureExitFinalized(bc, pubkey) + if err != nil { + if errors.Is(err, errExitNotFinalized) { + response.ExitNotFinalized = true + response.CanExit = false + return &response, nil + } + return nil, err } eth2Config, err := bc.GetEth2Config() @@ -65,7 +121,7 @@ func canNotifyValidatorExit(c *cli.Command, validatorId uint32) (*api.CanNotifyV return nil, err } - proof, slotTimestamp, slotProof, err := services.GetValidatorProof(c, 0, w, eth2Config, megapoolAddress, types.ValidatorPubkey(validatorInfo.Pubkey), nil) + proof, slotTimestamp, slotProof, err := services.GetValidatorProof(c, 0, w, eth2Config, megapoolAddress, pubkey, beaconState) if err != nil { return nil, err } @@ -83,7 +139,7 @@ func canNotifyValidatorExit(c *cli.Command, validatorId uint32) (*api.CanNotifyV // Update & return response response.GasLimits = gasLimits - response.CanExit = !response.InvalidStatus + response.CanExit = true return &response, nil } @@ -137,12 +193,19 @@ func notifyValidatorExit(c *cli.Command, validatorId uint32, opts *bind.Transact return nil, err } + pubkey := types.ValidatorPubkey(validatorInfo.Pubkey) + + beaconState, err := ensureExitFinalized(bc, pubkey) + if err != nil { + return nil, err + } + eth2Config, err := bc.GetEth2Config() if err != nil { return nil, err } - validatorProof, slotTimetamp, slotProof, err := services.GetValidatorProof(c, 0, w, eth2Config, megapoolAddress, types.ValidatorPubkey(validatorInfo.Pubkey), nil) + validatorProof, slotTimetamp, slotProof, err := services.GetValidatorProof(c, 0, w, eth2Config, megapoolAddress, pubkey, beaconState) if err != nil { return nil, err } diff --git a/rocketpool/api/megapool/reduce-bond.go b/rocketpool/api/megapool/reduce-bond.go index 6c35bbaaa..d9d7a675c 100644 --- a/rocketpool/api/megapool/reduce-bond.go +++ b/rocketpool/api/megapool/reduce-bond.go @@ -57,7 +57,7 @@ func canReduceBond(c *cli.Command, amount *big.Int) (*api.CanReduceBondResponse, } // Load the megapool details - details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil) + details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil, false) if err != nil { return nil, err } diff --git a/rocketpool/api/megapool/status.go b/rocketpool/api/megapool/status.go index 7c5ac3250..91d4035f7 100644 --- a/rocketpool/api/megapool/status.go +++ b/rocketpool/api/megapool/status.go @@ -1,11 +1,9 @@ package megapool import ( - "context" "fmt" "math/big" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/bindings/megapool" @@ -44,16 +42,7 @@ func getStatus(c *cli.Command, finalizedState bool) (*api.MegapoolStatusResponse if err != nil { return nil, err } - var opts *bind.CallOpts - - if finalizedState { - // We just need a non-nil opts for the next calls to use the finalized state - opts = &bind.CallOpts{ - Context: context.Background(), - } - } - - details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, opts) + details, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil, finalizedState) if err != nil { return nil, err } @@ -66,8 +55,18 @@ func getStatus(c *cli.Command, finalizedState bool) (*api.MegapoolStatusResponse } response.BeaconHead = beaconHead + // Beacon SHARD_COMMITTEE_PERIOD (for exit eligibility) + eth2Config, err := bc.GetEth2Config() + if err != nil { + return nil, fmt.Errorf("Error getting eth2 config: %w", err) + } + response.ShardCommitteePeriod = eth2Config.ShardCommitteePeriod + if response.ShardCommitteePeriod == 0 { + response.ShardCommitteePeriod = 256 + } + // Get latest delegate address - delegate, err := rp.GetContract("rocketMegapoolDelegate", opts) + delegate, err := rp.GetContract("rocketMegapoolDelegate", nil) if err != nil { return nil, fmt.Errorf("Error getting latest minipool delegate contract: %w", err) } diff --git a/rocketpool/api/node/deposit.go b/rocketpool/api/node/deposit.go index 31eef5389..936af69dc 100644 --- a/rocketpool/api/node/deposit.go +++ b/rocketpool/api/node/deposit.go @@ -112,7 +112,7 @@ func canNodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFe }) wg1.Go(func() error { - status, err = services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil) + status, err = services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil, false) if err != nil { return err } @@ -356,7 +356,7 @@ func nodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFee f return nil, err } - status, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil) + status, err := services.GetNodeMegapoolDetails(rp, bc, nodeAccount.Address, nil, false) if err != nil { return nil, err } diff --git a/rocketpool/node/defend-challenge-exit.go b/rocketpool/node/defend-challenge-exit.go index 10be87187..3a306e136 100644 --- a/rocketpool/node/defend-challenge-exit.go +++ b/rocketpool/node/defend-challenge-exit.go @@ -144,7 +144,7 @@ func (t *defendChallengeExit) run(state *state.NetworkState) error { if err != nil { return err } - validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts) + validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts, false) if err != nil { return err } diff --git a/rocketpool/node/defend-pdao-props.go b/rocketpool/node/defend-pdao-props.go index 6fe99331c..fab39d5a4 100644 --- a/rocketpool/node/defend-pdao-props.go +++ b/rocketpool/node/defend-pdao-props.go @@ -1,6 +1,7 @@ package node import ( + "context" "fmt" "math/big" "time" @@ -187,8 +188,16 @@ func (t *defendPdaoProps) getDefendableProposals(state *state.NetworkState, opts return nil, fmt.Errorf("beacon block at slot %d was missing", startSlot) } - // Get the EL block for this slot - startBlock = big.NewInt(int64(block.ExecutionBlockNumber)) + // Get the EL block for this slot. Gloas blocks only commit to the EL block hash, so the + // number has to be resolved. + elBlockNumber, hasElBlock, err := beacon.ResolveExecutionBlockNumber(context.Background(), t.rp.Client, block) + if err != nil { + return nil, err + } + if !hasElBlock { + return nil, fmt.Errorf("beacon block at slot %d has no execution block", startSlot) + } + startBlock = big.NewInt(int64(elBlockNumber)) } else { startBlock = big.NewInt(0).Add(t.lastScannedBlock, common.Big1) } diff --git a/rocketpool/node/notify-validator-exit.go b/rocketpool/node/notify-validator-exit.go index 5976d77f4..b96545211 100644 --- a/rocketpool/node/notify-validator-exit.go +++ b/rocketpool/node/notify-validator-exit.go @@ -3,6 +3,7 @@ package node import ( "fmt" "math/big" + "strconv" "github.com/docker/docker/client" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -171,14 +172,36 @@ func (t *notifyValidatorExit) run(state *state.NetworkState) error { if err != nil { return err } + finalizedValidators := beaconState.GetValidators() for validatorId, validatorDetails := range validatorDetailsToProve { + pubkey := types.ValidatorPubkey(validatorDetails.Pubkey) // Log t.log.Printlnf("The validator id %d needs an exit proof", validatorId) + // Check the exit is visible on the finalized state before proof generation + validatorIndexStr, err := t.bc.GetValidatorIndex(pubkey) + if err != nil { + t.log.Printlnf("Error getting beacon index for validator id %d: %w", validatorId, err) + continue + } + validatorIndex, err := strconv.ParseUint(validatorIndexStr, 10, 64) + if err != nil { + t.log.Printlnf("Error parsing beacon index for validator id %d: %w", validatorId, err) + continue + } + if validatorIndex >= uint64(len(finalizedValidators)) { + t.log.Printlnf("Validator id %d (beacon index %d) is not yet included in the finalized beacon state. Will retry on next cycle.", validatorId, validatorIndex) + continue + } + if finalizedValidators[validatorIndex].WithdrawableEpoch >= FarFutureEpoch { + t.log.Printlnf("Validator id %d (beacon index %d) exit is not yet reflected in the finalized beacon state (withdrawable_epoch still FAR_FUTURE). Will retry on next cycle.", validatorId, validatorIndex) + continue + } + // Call Notify Exit - err := t.createExitProof(t.rp, beaconState, mp, validatorId, state, types.ValidatorPubkey(validatorDetails.Pubkey), opts) + err = t.createExitProof(t.rp, beaconState, mp, validatorId, state, pubkey, opts) // dont return if there was an error, just log it so we can continue with the next validator if err != nil { t.log.Printlnf("Error creating exit proof for validator %d: %w", validatorId, err) diff --git a/rocketpool/node/stake-megapool-validator.go b/rocketpool/node/stake-megapool-validator.go index 1124fc47b..1866b5b56 100644 --- a/rocketpool/node/stake-megapool-validator.go +++ b/rocketpool/node/stake-megapool-validator.go @@ -145,7 +145,7 @@ func (t *stakeMegapoolValidator) run(state *state.NetworkState) error { if err != nil { return err } - validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts) + validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts, false) if err != nil { return err } diff --git a/rocketpool/node/verify-pdao-props-state_test.go b/rocketpool/node/verify-pdao-props-state_test.go index 14e9f4b5d..31f659fb5 100644 --- a/rocketpool/node/verify-pdao-props-state_test.go +++ b/rocketpool/node/verify-pdao-props-state_test.go @@ -1,10 +1,13 @@ package node import ( + "context" "math/big" "testing" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/types" log "github.com/rocket-pool/smartnode/shared/logger" @@ -28,6 +31,14 @@ func (s *stubBeaconClient) GetBeaconBlock(_ string) (beacon.BeaconBlock, bool, e return s.block, true, nil } +// stubExecutionHeaderSource stands in for the EC when resolving a Gloas payload hash. The +// fixtures all use blocks that already carry an EL block number, so this should never be hit. +type stubExecutionHeaderSource struct{} + +func (s *stubExecutionHeaderSource) HeaderByHash(_ context.Context, _ common.Hash) (*ethtypes.Header, error) { + return nil, ethereum.NotFound +} + // stubNodeGetter returns a fixed on-chain root for every proposal. type stubNodeGetter struct { root types.VotingTreeNode @@ -119,6 +130,7 @@ func TestChallengePathNoEligible(t *testing.T) { challenges, defeats, err := getChallengesFromState( ns, proposerAddr, &logger, &stubBeaconClient{block: beacon.BeaconBlock{ExecutionBlockNumber: ns.ElBlockNumber}}, + &stubExecutionHeaderSource{}, &stubNodeGetter{root: makeLocalRoot()}, &stubTreeProvider{}, &stubChallengeStateGetter{}, @@ -162,6 +174,7 @@ func TestChallengePathMatchingRoot(t *testing.T) { challenges, defeats, err := getChallengesFromState( ns, nodeAddr, &logger, &stubBeaconClient{block: beacon.BeaconBlock{ExecutionBlockNumber: ns.ElBlockNumber}}, + &stubExecutionHeaderSource{}, &stubNodeGetter{root: localRoot}, &stubTreeProvider{tree: localTree}, &stubChallengeStateGetter{}, @@ -240,6 +253,7 @@ func TestChallengePathMismatchProducesChallenge(t *testing.T) { challenges, defeats, err := getChallengesFromState( ns, nodeAddr, &logger, &stubBeaconClient{block: beacon.BeaconBlock{ExecutionBlockNumber: ns.ElBlockNumber}}, + &stubExecutionHeaderSource{}, &stubNodeGetter{root: makeMismatchedOnChainRoot()}, &stubTreeProvider{tree: localTree}, &stubChallengeStateGetter{}, @@ -320,6 +334,7 @@ func TestChallengePathAlreadyChallengedWaits(t *testing.T) { challenges, defeats, err := getChallengesFromState( ns, nodeAddr, &logger, &stubBeaconClient{block: beacon.BeaconBlock{ExecutionBlockNumber: ns.ElBlockNumber}}, + &stubExecutionHeaderSource{}, &stubNodeGetter{root: makeMismatchedOnChainRoot()}, &stubTreeProvider{tree: localTree}, csGetter, @@ -401,6 +416,7 @@ func TestChallengePathRespondedDelveDeeper(t *testing.T) { challenges, defeats, err := getChallengesFromState( ns, nodeAddr, &logger, &stubBeaconClient{block: beacon.BeaconBlock{ExecutionBlockNumber: ns.ElBlockNumber}}, + &stubExecutionHeaderSource{}, &stubNodeGetter{root: makeMismatchedOnChainRoot()}, &stubTreeProvider{tree: localTree}, csGetter, diff --git a/rocketpool/node/verify-pdao-props.go b/rocketpool/node/verify-pdao-props.go index fedb7546c..3f4f2a821 100644 --- a/rocketpool/node/verify-pdao-props.go +++ b/rocketpool/node/verify-pdao-props.go @@ -1,6 +1,7 @@ package node import ( + "context" "fmt" "math/big" "time" @@ -254,7 +255,7 @@ func (t *verifyPdaoProps) getChallengesandDefeats(ns *state.NetworkState, opts * artifactChecker := &liveChallengeArtifactChecker{propMgr: t.propMgr} return getChallengesFromState( - ns, t.nodeAddress, t.log, t.bc, + ns, t.nodeAddress, t.log, t.bc, t.rp.Client, nodeGetter, treeProvider, stateGetter, eventProvider, artifactChecker, t.validPropCache, t.rootSubmissionCache, t.lastScannedBlock, ) @@ -268,6 +269,7 @@ func getChallengesFromState( nodeAddress common.Address, log *log.ColorLogger, bc beacon.Client, + ec beacon.ExecutionHeaderSource, nodeGetter proposalNodeGetter, treeProvider networkTreeProvider, stateGetter challengeStateGetter, @@ -346,8 +348,16 @@ func getChallengesFromState( return nil, nil, fmt.Errorf("Beacon block at slot %d was missing", startSlot) } - // Get the EL block for this slot - startBlock = big.NewInt(int64(block.ExecutionBlockNumber)) + // Get the EL block for this slot. Gloas blocks only commit to the EL block hash, so the + // number has to be resolved. + elBlockNumber, hasElBlock, err := beacon.ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + return nil, nil, err + } + if !hasElBlock { + return nil, nil, fmt.Errorf("Beacon block at slot %d has no execution block", startSlot) + } + startBlock = big.NewInt(int64(elBlockNumber)) } else { startBlock = big.NewInt(0).Add(lastScannedBlock, common.Big1) } diff --git a/rocketpool/watchtower/submit-rewards-tree-stateless.go b/rocketpool/watchtower/submit-rewards-tree-stateless.go index 5f7183deb..08ed00444 100644 --- a/rocketpool/watchtower/submit-rewards-tree-stateless.go +++ b/rocketpool/watchtower/submit-rewards-tree-stateless.go @@ -382,9 +382,9 @@ func (t *submitRewardsTree_Stateless) submitRewardsSnapshot(index *big.Int, cons // Create the total rewards for each network for network := uint64(0); rewardsFile.HasRewardsForNetwork(network); network++ { - collateralRplRewards = append(collateralRplRewards, rewardsFile.GetNetworkCollateralRpl(network)) - oDaoRplRewards = append(oDaoRplRewards, rewardsFile.GetNetworkOracleDaoRpl(network)) - nodeOperatorSmoothingPoolEthRewardsAndVoterShare = append(nodeOperatorSmoothingPoolEthRewardsAndVoterShare, rewardsFile.GetNetworkSmoothingPoolEth(network)) + collateralRplRewards = append(collateralRplRewards, zeroIfNil(rewardsFile.GetNetworkCollateralRpl(network))) + oDaoRplRewards = append(oDaoRplRewards, zeroIfNil(rewardsFile.GetNetworkOracleDaoRpl(network))) + nodeOperatorSmoothingPoolEthRewardsAndVoterShare = append(nodeOperatorSmoothingPoolEthRewardsAndVoterShare, zeroIfNil(rewardsFile.GetNetworkSmoothingPoolEth(network))) } // Get transactor @@ -401,13 +401,13 @@ func (t *submitRewardsTree_Stateless) submitRewardsSnapshot(index *big.Int, cons ConsensusBlock: big.NewInt(0).SetUint64(consensusBlock), MerkleRoot: treeRoot, IntervalsPassed: intervalsPassed, - TreasuryETH: rewardsFile.GetTotalProtocolDaoEth(), - TreasuryRPL: rewardsFile.GetTotalProtocolDaoRpl(), + TreasuryETH: zeroIfNil(rewardsFile.GetTotalProtocolDaoEth()), + TreasuryRPL: zeroIfNil(rewardsFile.GetTotalProtocolDaoRpl()), NodeRPL: collateralRplRewards, TrustedNodeRPL: oDaoRplRewards, NodeETH: nodeOperatorSmoothingPoolEthRewardsAndVoterShare, - UserETH: rewardsFile.GetTotalPoolStakerSmoothingPoolEth(), - SmoothingPoolETH: rewardsFile.GetTotalSmoothingPoolBalance(), + UserETH: zeroIfNil(rewardsFile.GetTotalPoolStakerSmoothingPoolEth()), + SmoothingPoolETH: zeroIfNil(rewardsFile.GetTotalSmoothingPoolBalance()), } // Skip submission if the period has already reached consensus. @@ -452,6 +452,13 @@ func (t *submitRewardsTree_Stateless) submitRewardsSnapshot(index *big.Int, cons return true, nil } +func zeroIfNil(v *big.Int) *big.Int { + if v == nil { + return big.NewInt(0) + } + return v +} + // Get the first finalized, successful consensus block that occurred after the given target time func (t *submitRewardsTree_Stateless) getSnapshotEnd(endTime time.Time, state *state.NetworkState) (*rprewards.SnapshotEnd, error) { @@ -494,9 +501,20 @@ func (t *submitRewardsTree_Stateless) getSnapshotEnd(endTime time.Time, state *s continue } + // Gloas blocks only commit to the EL block hash, so the number has to be resolved + elBlockNumber, hasElBlock, err := beacon.ResolveExecutionBlockNumber(context.Background(), t.ec, block) + if err != nil { + return nil, err + } + if !hasElBlock { + t.log.Printlnf("Slot %d has no execution block, trying the previous one...", targetSlot) + targetSlot-- + continue + } + // Ok, we have the first proposed finalized block - this is the one to use for the snapshot! out.ConsensusBlock = targetSlot - out.ExecutionBlock = block.ExecutionBlockNumber + out.ExecutionBlock = elBlockNumber break } diff --git a/rocketpool/watchtower/utils/utils.go b/rocketpool/watchtower/utils/utils.go index de527c8b9..a70fe528f 100644 --- a/rocketpool/watchtower/utils/utils.go +++ b/rocketpool/watchtower/utils/utils.go @@ -37,20 +37,36 @@ func GetWatchtowerPrioFee(cfg *config.RocketPoolConfig) float64 { return max(MinWatchtowerPriorityFee, setting) } -func FindLastBlockWithExecutionPayload(bc beacon.Client, slotNumber uint64) (beacon.BeaconBlock, error) { - beaconBlock := beacon.BeaconBlock{} - var err error - for blockExists, searchSlot := false, slotNumber; !blockExists; searchSlot-- { - beaconBlock, blockExists, err = bc.GetBeaconBlock(strconv.FormatUint(searchSlot, 10)) - if err != nil { - return beacon.BeaconBlock{}, err - } +// Walks back from slotNumber until it finds a block that actually has an Execution Layer block +// behind it, and returns it with ExecutionBlockNumber populated. Gloas (EIP-7732) blocks carry +// only the payload bid's block hash, so the number is resolved through the EL. +func FindLastBlockWithExecutionPayload(bc beacon.Client, ec rocketpool.ExecutionClient, slotNumber uint64) (beacon.BeaconBlock, error) { + for searchSlot := slotNumber; ; searchSlot-- { // If we go back more than 32 slots, error out if slotNumber-searchSlot > 32 { return beacon.BeaconBlock{}, fmt.Errorf("could not find EL block from slot %d", slotNumber) } + + beaconBlock, blockExists, err := bc.GetBeaconBlock(strconv.FormatUint(searchSlot, 10)) + if err != nil { + return beacon.BeaconBlock{}, err + } + if !blockExists { + continue + } + + // Resolve the EL block number + elBlockNumber, found, err := beacon.ResolveExecutionBlockNumber(context.Background(), ec, beaconBlock) + if err != nil { + return beacon.BeaconBlock{}, err + } + if !found { + continue + } + + beaconBlock.ExecutionBlockNumber = elBlockNumber + return beaconBlock, nil } - return beaconBlock, nil } func FindNextSubmissionTarget(rp *rocketpool.RocketPool, eth2Config beacon.Eth2Config, bc beacon.Client, ec rocketpool.ExecutionClient, lastSubmissionBlock uint64, referenceTimestamp int64, submissionIntervalInSeconds int64) (uint64, time.Time, *types.Header, bool, error) { @@ -99,7 +115,7 @@ func FindNextSubmissionTarget(rp *rocketpool.RocketPool, eth2Config beacon.Eth2C slotNumber := uint64(timeSinceGenesis.Seconds()) / eth2Config.SecondsPerSlot // Search for the last existing EL block, going back up to 32 slots if the block is not found. - targetBlock, err := FindLastBlockWithExecutionPayload(bc, slotNumber) + targetBlock, err := FindLastBlockWithExecutionPayload(bc, ec, slotNumber) if err != nil { return 0, time.Time{}, nil, false, err } diff --git a/shared/services/beacon/client.go b/shared/services/beacon/client.go index d5dae06f8..b80ec67ad 100644 --- a/shared/services/beacon/client.go +++ b/shared/services/beacon/client.go @@ -63,6 +63,7 @@ type BeaconBlock struct { Attestations []AttestationInfo FeeRecipient common.Address ExecutionBlockNumber uint64 + ExecutionBlockHash common.Hash Withdrawals []WithdrawalInfo } type BeaconBlockHeader struct { diff --git a/shared/services/beacon/client/std-http-client.go b/shared/services/beacon/client/std-http-client.go index 29ffd0781..1be45696d 100644 --- a/shared/services/beacon/client/std-http-client.go +++ b/shared/services/beacon/client/std-http-client.go @@ -135,6 +135,10 @@ func (c *StandardHttpClient) GetEth2Config() (beacon.Eth2Config, error) { } // Save the result + shardCommitteePeriod := uint64(eth2Config.Data.ShardCommitteePeriod) + if shardCommitteePeriod == 0 { + shardCommitteePeriod = 256 + } out := beacon.Eth2Config{ GenesisForkVersion: genesis.Data.GenesisForkVersion, GenesisValidatorsRoot: genesis.Data.GenesisValidatorsRoot, @@ -144,6 +148,7 @@ func (c *StandardHttpClient) GetEth2Config() (beacon.Eth2Config, error) { SlotsPerEpoch: uint64(eth2Config.Data.SlotsPerEpoch), SecondsPerEpoch: uint64(eth2Config.Data.SecondsPerSlot * eth2Config.Data.SlotsPerEpoch), EpochsPerSyncCommitteePeriod: uint64(eth2Config.Data.EpochsPerSyncCommitteePeriod), + ShardCommitteePeriod: shardCommitteePeriod, } eth2ConfigCache.Store(&out) @@ -652,13 +657,23 @@ func (c *StandardHttpClient) GetBeaconBlock(blockId string) (beacon.BeaconBlock, ProposerIndex: block.Data.Message.ProposerIndex, } - // Execution payload only exists after the merge, so check for its existence - if block.Data.Message.Body.ExecutionPayload == nil { - beaconBlock.HasExecutionPayload = false - } else { + // Pre-Gloas: execution payload is embedded in the block body. + // Gloas (EIP-7732 ePBS): payload is uncoupled; the body only carries a + // signed_execution_payload_bid with fee_recipient + block_hash. + executionPayload := block.Data.Message.Body.ExecutionPayload + payloadBid := block.Data.Message.Body.SignedExecutionPayloadBid + if executionPayload != nil { beaconBlock.HasExecutionPayload = true - beaconBlock.FeeRecipient = common.BytesToAddress(block.Data.Message.Body.ExecutionPayload.FeeRecipient) - beaconBlock.ExecutionBlockNumber = uint64(block.Data.Message.Body.ExecutionPayload.BlockNumber) + beaconBlock.FeeRecipient = common.BytesToAddress(executionPayload.FeeRecipient) + beaconBlock.ExecutionBlockNumber = uint64(executionPayload.BlockNumber) + } else if payloadBid != nil && payloadBid.Message != nil { + beaconBlock.HasExecutionPayload = true + beaconBlock.FeeRecipient = common.BytesToAddress(payloadBid.Message.FeeRecipient) + if len(payloadBid.Message.BlockHash) > 0 { + beaconBlock.ExecutionBlockHash = common.BytesToHash(payloadBid.Message.BlockHash) + } + } else { + beaconBlock.HasExecutionPayload = false } // Add attestation info @@ -684,20 +699,25 @@ func (c *StandardHttpClient) GetBeaconBlock(blockId string) (beacon.BeaconBlock, beaconBlock.Attestations = append(beaconBlock.Attestations, info) } - // Add withdrawals - beaconBlock.Withdrawals = make([]beacon.WithdrawalInfo, 0, len(block.Data.Message.Body.ExecutionPayload.Withdrawals)) - for _, withdrawal := range block.Data.Message.Body.ExecutionPayload.Withdrawals { - amount, ok := new(big.Int).SetString(withdrawal.Amount, 10) - if !ok { - return beacon.BeaconBlock{}, false, fmt.Errorf("Error decoding withdrawal amount for withdrawal for address %s of block %s: %s", withdrawal.Address, blockId, withdrawal.Amount) + // Withdrawals only exist on the embedded execution payload (pre-Gloas). + // Gloas withdrawals live on the EL block / beacon state expected_withdrawals. + if executionPayload != nil { + beaconBlock.Withdrawals = make([]beacon.WithdrawalInfo, 0, len(executionPayload.Withdrawals)) + for _, withdrawal := range executionPayload.Withdrawals { + amount, ok := new(big.Int).SetString(withdrawal.Amount, 10) + if !ok { + return beacon.BeaconBlock{}, false, fmt.Errorf("Error decoding withdrawal amount for withdrawal for address %s of block %s: %s", withdrawal.Address, blockId, withdrawal.Amount) + } + // amount is in Gwei, but we want wei + amount.Mul(amount, big.NewInt(1e9)) + beaconBlock.Withdrawals = append(beaconBlock.Withdrawals, beacon.WithdrawalInfo{ + ValidatorIndex: withdrawal.ValidatorIndex, + Address: common.BytesToAddress(withdrawal.Address), + Amount: amount, + }) } - // amount is in Gwei, but we want wei - amount.Mul(amount, big.NewInt(1e9)) - beaconBlock.Withdrawals = append(beaconBlock.Withdrawals, beacon.WithdrawalInfo{ - ValidatorIndex: withdrawal.ValidatorIndex, - Address: common.BytesToAddress(withdrawal.Address), - Amount: amount, - }) + } else { + beaconBlock.Withdrawals = []beacon.WithdrawalInfo{} } return beaconBlock, true, nil diff --git a/shared/services/beacon/client/types.go b/shared/services/beacon/client/types.go index 9347a0a54..1240582cb 100644 --- a/shared/services/beacon/client/types.go +++ b/shared/services/beacon/client/types.go @@ -45,6 +45,7 @@ type Eth2ConfigResponse struct { SlotsPerEpoch uinteger `json:"SLOTS_PER_EPOCH"` CapellaForkVersion byteArray `json:"CAPELLA_FORK_VERSION"` EpochsPerSyncCommitteePeriod uinteger `json:"EPOCHS_PER_SYNC_COMMITTEE_PERIOD"` + ShardCommitteePeriod uinteger `json:"SHARD_COMMITTEE_PERIOD"` } `json:"data"` } type Eth2DepositContractResponse struct { @@ -100,6 +101,14 @@ type BeaconBlockResponse struct { BlockNumber uinteger `json:"block_number"` Withdrawals []Withdrawal `json:"withdrawals"` } `json:"execution_payload"` + // Gloas (EIP-7732 ePBS): execution payload is no longer embedded + // in the beacon block; only a signed bid with the payload hash. + SignedExecutionPayloadBid *struct { + Message *struct { + FeeRecipient byteArray `json:"fee_recipient"` + BlockHash byteArray `json:"block_hash"` + } `json:"message"` + } `json:"signed_execution_payload_bid"` } `json:"body"` } `json:"message"` } `json:"data"` diff --git a/shared/services/beacon/config.go b/shared/services/beacon/config.go index ad96d0d23..e94ec9561 100644 --- a/shared/services/beacon/config.go +++ b/shared/services/beacon/config.go @@ -17,6 +17,7 @@ type Eth2Config struct { SlotsPerEpoch uint64 `json:"slots_per_epoch"` SecondsPerEpoch uint64 `json:"seconds_per_epoch"` EpochsPerSyncCommitteePeriod uint64 `json:"epochs_per_sync_committee_period"` + ShardCommitteePeriod uint64 `json:"shard_committee_period"` } func (c *Eth2Config) MarshalJSON() ([]byte, error) { diff --git a/shared/services/beacon/execution.go b/shared/services/beacon/execution.go new file mode 100644 index 000000000..63de90510 --- /dev/null +++ b/shared/services/beacon/execution.go @@ -0,0 +1,51 @@ +package beacon + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// The subset of the Execution Client needed to resolve a payload hash into a block number. +// Kept minimal so that Execution Client managers, the raw client interface, and test stubs +// all satisfy it without any of them having to be imported here. +type ExecutionHeaderSource interface { + // HeaderByHash returns the block header with the given hash. + HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) +} + +// ResolveExecutionBlockNumber returns the Execution Layer block number associated with a Beacon +// block. +// +// Pre-Gloas blocks embed the number in the execution payload. Gloas (EIP-7732) blocks no longer +// carry the payload at all - the body only has a bid committing to the payload's block hash - so +// the number has to be resolved through the Execution Client. +func ResolveExecutionBlockNumber(ctx context.Context, ec ExecutionHeaderSource, block BeaconBlock) (uint64, bool, error) { + + // Pre-Gloas: the payload was embedded in the block, so the number is already known. + if block.ExecutionBlockNumber != 0 { + return block.ExecutionBlockNumber, true, nil + } + + // No payload association at all + if block.ExecutionBlockHash == (common.Hash{}) { + return 0, false, nil + } + + header, err := ec.HeaderByHash(ctx, block.ExecutionBlockHash) + if err != nil { + if errors.Is(err, ethereum.NotFound) { + return 0, false, nil + } + return 0, false, fmt.Errorf("error resolving EL block for payload hash %s at slot %d: %w", block.ExecutionBlockHash.Hex(), block.Slot, err) + } + if header == nil || header.Number == nil { + return 0, false, nil + } + + return header.Number.Uint64(), true, nil +} diff --git a/shared/services/beacon/execution_test.go b/shared/services/beacon/execution_test.go new file mode 100644 index 000000000..e8c89d6f7 --- /dev/null +++ b/shared/services/beacon/execution_test.go @@ -0,0 +1,135 @@ +package beacon + +import ( + "context" + "errors" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type stubHeaderSource struct { + headers map[common.Hash]*types.Header + err error + calls int +} + +func (s *stubHeaderSource) HeaderByHash(_ context.Context, hash common.Hash) (*types.Header, error) { + s.calls++ + if s.err != nil { + return nil, s.err + } + if header, ok := s.headers[hash]; ok { + return header, nil + } + return nil, ethereum.NotFound +} + +func TestResolveExecutionBlockNumberUsesEmbeddedNumber(t *testing.T) { + ec := &stubHeaderSource{} + block := BeaconBlock{ + Slot: 100, + HasExecutionPayload: true, + ExecutionBlockNumber: 4242, + } + + number, found, err := ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !found { + t.Error("expected found for a block with an embedded number") + } + if number != 4242 { + t.Errorf("expected block 4242, got %d", number) + } + // Pre-Gloas blocks must not cost an extra EL round trip, and snapshot mode depends on it + if ec.calls != 0 { + t.Errorf("expected no EL calls for an embedded number, got %d", ec.calls) + } +} + +func TestResolveExecutionBlockNumberNoPayload(t *testing.T) { + ec := &stubHeaderSource{} + block := BeaconBlock{Slot: 100} + + number, found, err := ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if found { + t.Error("expected not found for a block with no payload association") + } + if number != 0 { + t.Errorf("expected block 0, got %d", number) + } + if ec.calls != 0 { + t.Errorf("expected no EL calls with an empty hash, got %d", ec.calls) + } +} + +func TestResolveExecutionBlockNumberFromHash(t *testing.T) { + hash := common.HexToHash("0xabc123") + ec := &stubHeaderSource{ + headers: map[common.Hash]*types.Header{ + hash: {Number: big.NewInt(9001)}, + }, + } + block := BeaconBlock{ + Slot: 100, + HasExecutionPayload: true, + ExecutionBlockHash: hash, + } + + number, found, err := ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !found { + t.Error("expected found for a resolvable payload hash") + } + if number != 9001 { + t.Errorf("expected block 9001, got %d", number) + } +} + +func TestResolveExecutionBlockNumberPayloadWithheld(t *testing.T) { + ec := &stubHeaderSource{} + block := BeaconBlock{ + Slot: 100, + HasExecutionPayload: true, + ExecutionBlockHash: common.HexToHash("0xdeadbeef"), + } + + number, found, err := ResolveExecutionBlockNumber(context.Background(), ec, block) + if err != nil { + t.Fatalf("expected no error for a withheld payload, got %v", err) + } + if found { + t.Error("expected not found for a withheld payload") + } + if number != 0 { + t.Errorf("expected block 0, got %d", number) + } +} + +func TestResolveExecutionBlockNumberPropagatesErrors(t *testing.T) { + sentinel := errors.New("execution client is offline") + ec := &stubHeaderSource{err: sentinel} + block := BeaconBlock{ + Slot: 100, + HasExecutionPayload: true, + ExecutionBlockHash: common.HexToHash("0xabc123"), + } + + _, found, err := ResolveExecutionBlockNumber(context.Background(), ec, block) + if !errors.Is(err, sentinel) { + t.Fatalf("expected the EL error to be wrapped, got %v", err) + } + if found { + t.Error("expected not found on error") + } +} diff --git a/shared/services/config/smartnode-config.go b/shared/services/config/smartnode-config.go index 26b727363..e55f13334 100644 --- a/shared/services/config/smartnode-config.go +++ b/shared/services/config/smartnode-config.go @@ -3,7 +3,6 @@ package config import ( "fmt" "path/filepath" - "strings" "github.com/ethereum/go-ethereum/common" @@ -13,10 +12,20 @@ import ( // Constants const ( - smartnodeTagPrefix string = "rocketpool/smartnode:v" - NetworkID string = "network" - ProjectNameID string = "projectName" - SnapshotID string = "rocketpool-dao.eth" + smartnodeTagPrefix string = "rocketpool/smartnode:v" + NetworkID string = "network" + ProjectNameID string = "projectName" + SnapshotID string = "rocketpool-dao.eth" + + kurtosisDevnetChainIDDefault uint = 3151908 + kurtosisDevnetStorageAddressDefault string = "0xb4B46bdAA835F8E4b4d8e208B6559cD267851051" + kurtosisDevnetRplAddressDefault string = "0x2b45cD38B213Bbd3A1A848bf2467927c976877Cb" + kurtosisDevnetRethAddressDefault string = "0x80741a37E3644612F0465145C9709a90B6D77Ee3" + kurtosisDevnetMulticallAddressDefault string = "0x2f06c1dA6987BfD39A0539c03F9274fFb1F5fa19" + kurtosisDevnetBalanceBatcherAddressDefault string = "0x1a0E9eF9Cc41f4CcD377979C0e6DC8dBe4E2858C" + kurtosisDevnetSignerRegistryAddressDefault string = "0x8f22b1Cd26efe83ADf8Da87789fB66EeD917FCAa" + kurtosisDevnetRplTwapPoolAddressDefault string = "0xdF321a81D594c6eD056E0DC3CB74AAEE4DcD91Fb" + rewardsTreeFilenameFormat string = "rp-rewards-%s-%d%s" minipoolPerformanceFilenameFormat string = "rp-minipool-performance-%s-%d%s" performanceFilenameFormat string = "rp-performance-%s-%d%s" @@ -433,43 +442,43 @@ func NewSmartnodeConfig(cfg *RocketPoolConfig) *SmartnodeConfig { txWatchUrl: map[config.Network]string{ config.Network_Mainnet: "https://etherscan.io/tx", - config.Network_Devnet: "https://hoodi.etherscan.io/tx", + config.Network_Devnet: "", config.Network_Testnet: "https://hoodi.etherscan.io/tx", }, nodeManagerUrl: map[config.Network]string{ config.Network_Mainnet: "https://node.rocketpool.net", - config.Network_Devnet: "https://devnet.node.rocketpool.net", + config.Network_Devnet: "", config.Network_Testnet: "https://testnet.node.rocketpool.net", }, chainID: map[config.Network]uint{ - config.Network_Mainnet: 1, // Mainnet - config.Network_Devnet: 560048, // Hoodi - config.Network_Testnet: 560048, // Hoodi + config.Network_Mainnet: 1, // Mainnet + config.Network_Devnet: kurtosisDevnetChainIDDefault, // Kurtosis ethereum-package (was Hoodi) + config.Network_Testnet: 560048, // Hoodi }, storageAddress: map[config.Network]string{ config.Network_Mainnet: "0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46", - config.Network_Devnet: "0x990BC2c12d2a39e5FD92111B98A728bf39742478", + config.Network_Devnet: kurtosisDevnetStorageAddressDefault, config.Network_Testnet: "0x594Fb75D3dc2DFa0150Ad03F99F97817747dd4E1", }, rocketSignerRegistryAddress: map[config.Network]string{ config.Network_Mainnet: "0xc1062617d10Ae99E09D941b60746182A87eAB38F", - config.Network_Devnet: "0xE3FbfaD4A11777E6271921E7EC1A5a1345684F4E", + config.Network_Devnet: kurtosisDevnetSignerRegistryAddressDefault, config.Network_Testnet: "0xE3FbfaD4A11777E6271921E7EC1A5a1345684F4E", }, rplTokenAddress: map[config.Network]string{ config.Network_Mainnet: "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", - config.Network_Devnet: "0xce59520Cbaec3B399a5245e72C0F21df791202FE", + config.Network_Devnet: kurtosisDevnetRplAddressDefault, config.Network_Testnet: "0x1Cc9cF5586522c6F483E84A19c3C2B0B6d027bF0", }, rethAddress: map[config.Network]string{ config.Network_Mainnet: "0xae78736Cd615f374D3085123A210448E74Fc6393", - config.Network_Devnet: "0x3aC886F531BEb95f08F73fDb21528BE3c63AA82F", + config.Network_Devnet: kurtosisDevnetRethAddressDefault, config.Network_Testnet: "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", }, @@ -551,9 +560,8 @@ func NewSmartnodeConfig(cfg *RocketPoolConfig) *SmartnodeConfig { common.HexToAddress("0xA805d68b61956BC92d556F2bE6d18747adAeEe82"), common.HexToAddress("0xEE4d2A71cF479e0D3d0c3c2C923dbfEB57E73111"), }, - config.Network_Devnet: { - common.HexToAddress("0x556791EC1aa443df339E340E6f20d06a1cD21583"), - }, + // Fresh private deploy — no legacy rewards pool history. + config.Network_Devnet: {}, config.Network_Testnet: { common.HexToAddress("0x4a625C617a44E60F74E3fe3bf6d6333b63766e91"), }, @@ -617,25 +625,25 @@ func NewSmartnodeConfig(cfg *RocketPoolConfig) *SmartnodeConfig { rplTwapPoolAddress: map[config.Network]string{ config.Network_Mainnet: "0xe42318ea3b998e8355a3da364eb9d48ec725eb45", - config.Network_Devnet: "0x0ca239d8AC5E49E3203d60eaf86Baa6712E5b454", + config.Network_Devnet: kurtosisDevnetRplTwapPoolAddressDefault, config.Network_Testnet: "0x0ca239d8AC5E49E3203d60eaf86Baa6712E5b454", }, multicallAddress: map[config.Network]string{ config.Network_Mainnet: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696", - config.Network_Devnet: "0xc5fA61aA6Ec012d1A2Ea38f31ADAf4D06c8725E7", + config.Network_Devnet: kurtosisDevnetMulticallAddressDefault, config.Network_Testnet: "0xc5fA61aA6Ec012d1A2Ea38f31ADAf4D06c8725E7", }, balancebatcherAddress: map[config.Network]string{ config.Network_Mainnet: "0xb1f8e55c7f64d203c1400b9d8555d050f94adf39", - config.Network_Devnet: "0xB80b500CF68a956b6f149F1C48E8F07EEF4486Ce", + config.Network_Devnet: kurtosisDevnetBalanceBatcherAddressDefault, config.Network_Testnet: "0xB80b500CF68a956b6f149F1C48E8F07EEF4486Ce", }, flashbotsProtectUrl: map[config.Network]string{ config.Network_Mainnet: "https://rpc.flashbots.net/", - config.Network_Devnet: "https://rpc-hoodi.flashbots.net/", + config.Network_Devnet: "", config.Network_Testnet: "https://rpc-hoodi.flashbots.net/", }, @@ -1015,14 +1023,11 @@ func getNetworkOptions() []config.ParameterOption { Description: "This is the Hoodi test network, which is the next generation of long-lived testnets for Ethereum. It uses free fake ETH and free fake RPL to make fake validators.\nUse this if you want to practice running the Smart Node in a free, safe environment before moving to Mainnet.", Value: config.Network_Testnet, }, - } - - if strings.Contains(shared.RocketPoolVersion(), "dev") { - options = append(options, config.ParameterOption{ + { Name: "Devnet", - Description: "This is a development network used by Rocket Pool engineers to test new features and contract upgrades before they are promoted to a Testnet for staging. You should not use this network unless invited to do so by the developers.", + Description: "Rocket Pool development network. This is a local network that is used for development and testing. It uses free fake ETH and free fake RPL to make fake validators.", Value: config.Network_Devnet, - }) + }, } return options diff --git a/shared/services/ec-manager.go b/shared/services/ec-manager.go index a57172cea..af62e9e62 100644 --- a/shared/services/ec-manager.go +++ b/shared/services/ec-manager.go @@ -179,6 +179,21 @@ func (p *ExecutionClientManager) HeaderByNumber(ctx context.Context, number *big return result.(*types.Header), err } +// BlockByNumber returns a block from the current canonical chain. If number is nil, the latest known block is +// returned. +func (p *ExecutionClientManager) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { + if p.static != nil { + return nil, fmt.Errorf("BlockByNumber is not supported by the static execution client") + } + result, err := p.runFunction(func(client *EthClient) (interface{}, error) { + return client.BlockByNumber(ctx, number) + }) + if err != nil { + return nil, err + } + return result.(*types.Block), err +} + // PendingCodeAt returns the code of the given account in the pending state. func (p *ExecutionClientManager) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { if p.static != nil { diff --git a/shared/services/megapools.go b/shared/services/megapools.go index f982645ea..42c91ef9a 100644 --- a/shared/services/megapools.go +++ b/shared/services/megapools.go @@ -1,6 +1,7 @@ package services import ( + "context" "encoding/json" "fmt" "io" @@ -8,11 +9,13 @@ import ( "math/big" "net/http" "strconv" + "strings" "sync" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/pk910/dynamic-ssz/treeproof" "github.com/urfave/cli/v3" @@ -32,11 +35,16 @@ import ( cfgtypes "github.com/rocket-pool/smartnode/shared/types/config" "github.com/rocket-pool/smartnode/shared/types/eth2" "github.com/rocket-pool/smartnode/shared/types/eth2/fork/fulu" + "github.com/rocket-pool/smartnode/shared/types/eth2/fork/gloas" "github.com/rocket-pool/smartnode/shared/types/eth2/generic" ) const MAX_WITHDRAWAL_SLOT_DISTANCE = 144000 // 20 days. +// gloasForkName is the Eth-Consensus-Version reported for the Gloas fork +// (ePBS, EIP-7732). +const gloasForkName = "gloas" + // API URL for the withdrawal proofs (base URL + network + withdrawal slot + validator index) const apiURL = "https://api.rocketpool.net/%s/withdrawals/proofs/%d/%d/%d" @@ -228,7 +236,7 @@ func CalculateMegapoolWithdrawalCredentials(megapoolAddress common.Address) comm } // Get all node megapool details -func GetNodeMegapoolDetails(rp *rocketpool.RocketPool, bc beacon.Client, nodeAccount common.Address, opts *bind.CallOpts) (api.MegapoolDetails, error) { +func GetNodeMegapoolDetails(rp *rocketpool.RocketPool, bc beacon.Client, nodeAccount common.Address, opts *bind.CallOpts, useFinalizedBeaconState bool) (api.MegapoolDetails, error) { megapoolAddress, err := megapool.GetMegapoolExpectedAddress(rp, nodeAccount, nil) if err != nil { @@ -393,7 +401,7 @@ func GetNodeMegapoolDetails(rp *rocketpool.RocketPool, bc beacon.Client, nodeAcc return details, err } - details.Validators, err = GetMegapoolValidatorDetails(rp, bc, mega, megapoolAddress, uint32(details.ValidatorCount), opts) + details.Validators, err = GetMegapoolValidatorDetails(rp, bc, mega, megapoolAddress, uint32(details.ValidatorCount), opts, useFinalizedBeaconState) if err != nil { return details, err } @@ -479,7 +487,7 @@ func CalculateRewards(rp *rocketpool.RocketPool, amount *big.Int, nodeAccount co } -func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp megapool.Megapool, megapoolAddress common.Address, validatorCount uint32, opts *bind.CallOpts) ([]api.MegapoolValidatorDetails, error) { +func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp megapool.Megapool, megapoolAddress common.Address, validatorCount uint32, opts *bind.CallOpts, useFinalizedBeaconState bool) ([]api.MegapoolValidatorDetails, error) { details := []api.MegapoolValidatorDetails{} @@ -492,12 +500,17 @@ func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp return details, fmt.Errorf("Error getting the megapool queue details: %w", err) } + // Beacon view: head by default, or the finalized epoch when the caller requested the finalized state + var statusOpts *beacon.ValidatorStatusOptions head, err := bc.GetBeaconHead() - if err == nil { - currentEpoch = head.Epoch - } - if opts != nil { + if useFinalizedBeaconState { + if err != nil { + return details, fmt.Errorf("Error getting the beacon head: %w", err) + } currentEpoch = head.FinalizedEpoch + statusOpts = &beacon.ValidatorStatusOptions{Epoch: ¤tEpoch} + } else if err == nil { + currentEpoch = head.Epoch } for i := uint32(0); i < validatorCount; i++ { @@ -526,7 +539,7 @@ func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp } // Try to fetch the validator status. If it fails, we assume the first deposit was not processed yet - validator.BeaconStatus, _ = bc.GetValidatorStatus(validator.PubKey, nil) + validator.BeaconStatus, _ = bc.GetValidatorStatus(validator.PubKey, statusOpts) if validator.Staked { if currentEpoch > validator.BeaconStatus.ActivationEpoch { validator.Activated = true @@ -698,6 +711,18 @@ func GetWithdrawalProofForSlot(c *cli.Command, slot uint64, validatorIndex uint6 return megapool.FinalBalanceProof{}, 0, nil, err } + // Gloas (ePBS) removed the execution payload from beacon blocks, so + // withdrawals can no longer be found in, or proven against, a beacon block. + // Resolve the fork at the finalized checkpoint and use the state-based proof + // flow when Gloas is active. + finalizedSlot, finalizedFork, err := GetFinalizedBlockSlotAndFork(bc) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + if strings.EqualFold(finalizedFork, gloasForkName) { + return getGloasWithdrawalProofForSlot(c, bc, slot, validatorIndex, finalizedSlot) + } + withdrawalSlot, block, indexInWithdrawalsArray, withdrawal, finalizedBlock, err := FindWithdrawalBlockAndArrayPosition(slot, validatorIndex, bc) if err != nil { return megapool.FinalBalanceProof{}, 0, nil, err @@ -815,6 +840,303 @@ func GetWithdrawalProofForSlot(c *cli.Command, slot uint64, validatorIndex uint6 return response, finalizedBlock.Slot, beaconState, nil } +// GetFinalizedBlockSlotAndFork resolves the slot and consensus fork version of +// the most recent finalized beacon block, walking back over skipped slots. The +// JSON block endpoint is intentionally avoided: it dereferences the execution +// payload, which no longer exists in Gloas blocks. +func GetFinalizedBlockSlotAndFork(bc beacon.Client) (uint64, string, error) { + head, err := bc.GetBeaconHead() + if err != nil { + return 0, "", err + } + eth2Config, err := bc.GetEth2Config() + if err != nil { + return 0, "", err + } + + candidate := head.FinalizedEpoch * eth2Config.SlotsPerEpoch + const maxAttempts = 64 // Two epochs + for attempts := 0; attempts < maxAttempts; attempts++ { + blockResponse, found, err := bc.GetBeaconBlockSSZ(candidate) + if err != nil { + return 0, "", err + } + if found { + fork := blockResponse.Fork + _ = blockResponse.Data.Close() + return candidate, fork, nil + } + if candidate == 0 { + break + } + candidate-- + } + return 0, "", fmt.Errorf("failed to find a finalized beacon block within %d slots of finalized epoch %d", maxAttempts, head.FinalizedEpoch) +} + +// getGloasWithdrawalProofForSlot builds a final-balance withdrawal proof for a +// Gloas (post-ePBS) chain. Pre-Gloas, a withdrawal is proven against the +// execution payload in the beacon block that carried it, and that block's root +// is anchored in a finalized state. In Gloas the payload is no longer part of +// the block; instead, the post-state of the withdrawal slot commits to the +// payload's withdrawals in payload_expected_withdrawals (see +// process_withdrawals / update_payload_expected_withdrawals in EIP-7732). The +// proof therefore chains: +// +// 1. withdrawal -> payload_expected_withdrawals -> state root of the withdrawal slot +// 2. state root of the withdrawal slot -> finalized state root, via +// state_roots (recent slots) or historical_summaries (historical slots) +// 3. finalized state root -> finalized block root (block header proof), which +// is what the contract checks against the EIP-4788 beacon roots oracle +// +// The witness layout mirrors the pre-Gloas one: +// +// recent: [expected_withdrawal, state_roots, block_header] +// historical: [expected_withdrawal, summary_state_root, historical_summary, block_header] +func getGloasWithdrawalProofForSlot(c *cli.Command, bc beacon.Client, slot uint64, validatorIndex uint64, finalizedSlot uint64) (megapool.FinalBalanceProof, uint64, eth2.BeaconState, error) { + // Create a new response + response := megapool.FinalBalanceProof{} + response.ValidatorIndex = validatorIndex + + ec, err := GetEthClient(c) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + eth2Config, err := bc.GetEth2Config() + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + // Find the payload that carried the withdrawal on the execution layer and + // map it back to the consensus slot whose state committed to it. + withdrawalSlot, indexInWithdrawalsArray, withdrawal, err := FindGloasWithdrawalSlotAndArrayPosition(slot, validatorIndex, ec, eth2Config) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + response.WithdrawalSlot = withdrawalSlot + response.Amount = big.NewInt(0).SetUint64(withdrawal.Amount) + response.IndexInWithdrawalsArray = uint(indexInWithdrawalsArray) + response.WithdrawalIndex = withdrawal.Index + response.WithdrawalAddress = withdrawal.Address + + // The state at the withdrawal slot commits to the payload's withdrawals in + // payload_expected_withdrawals; prove the withdrawal against its root. + withdrawalStateResponse, err := bc.GetBeaconStateSSZ(withdrawalSlot) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + withdrawalState, err := eth2.NewBeaconState(withdrawalStateResponse.Data, withdrawalStateResponse.Size, withdrawalStateResponse.Fork) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + gloasWithdrawalState, ok := withdrawalState.(*gloas.BeaconState) + if !ok { + // TODO: Check when the withdrawal predates the Gloas fork while finality is past it. + return megapool.FinalBalanceProof{}, 0, nil, fmt.Errorf("withdrawal slot %d is in the %s fork but finality is in gloas; cross-fork withdrawal proofs are not supported yet", withdrawalSlot, withdrawalStateResponse.Fork) + } + + // Sanity check that the withdrawal found on the EL matches the entry the + // beacon state committed to at the same position. + if err := verifyExpectedWithdrawal(gloasWithdrawalState, indexInWithdrawalsArray, withdrawal); err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + withdrawalProof, err := gloasWithdrawalState.ProveExpectedWithdrawal(uint64(indexInWithdrawalsArray)) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + // Get the finalized beacon state to anchor the withdrawal slot's state root. + stateResponse, err := bc.GetBeaconStateSSZ(finalizedSlot) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + beaconState, err := eth2.NewBeaconState(stateResponse.Data, stateResponse.Size, stateResponse.Fork) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + gloasState, ok := beaconState.(*gloas.BeaconState) + if !ok { + return megapool.FinalBalanceProof{}, 0, nil, fmt.Errorf("expected gloas.BeaconState, got %T", beaconState) + } + + var finalProof [][]byte + if withdrawalSlot+generic.SlotsPerHistoricalRoot > finalizedSlot { + // Recent slot: the finalized state's state_roots ring still holds the + // withdrawal slot's post-state root. + stateRootsProof, err := gloasState.StateRootProof(withdrawalSlot) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + blockHeaderProof, err := gloasState.BlockHeaderProof() + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + finalProof = append(finalProof, withdrawalProof...) + finalProof = append(finalProof, stateRootsProof...) + finalProof = append(finalProof, blockHeaderProof...) + } else { + // Historical slot: use historical_summaries. The era-aligned state's + // state_roots ring holds the whole era containing the withdrawal slot. + blockRootsStateSlot := generic.SlotsPerHistoricalRoot + ((withdrawalSlot / generic.SlotsPerHistoricalRoot) * generic.SlotsPerHistoricalRoot) + blockRootsStateResponse, err := bc.GetBeaconStateSSZ(blockRootsStateSlot) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + blockRootsState, err := eth2.NewBeaconState(blockRootsStateResponse.Data, blockRootsStateResponse.Size, blockRootsStateResponse.Fork) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + gloasBlockRootsState, ok := blockRootsState.(*gloas.BeaconState) + if !ok { + return megapool.FinalBalanceProof{}, 0, nil, fmt.Errorf("expected gloas.BeaconState for the era-aligned state, got %T", blockRootsState) + } + summaryStateRootProof, err := gloasBlockRootsState.HistoricalSummaryStateRootProof(int(withdrawalSlot)) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + // Prove the HistoricalSummary itself in the finalized state, navigating + // the EIP-7688 ProgressiveContainer with the Gloas g-indices. As in the + // pre-Gloas flow above, the block-header proof stays a separate final + // segment (the state's latest block header has a zeroed state root at + // the block's own slot, so it must be recomputed). + tree, err := generic.SSZ.GetTree(gloasState) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, fmt.Errorf("could not get state tree: %w", err) + } + arrayIndex := withdrawalSlot / generic.SlotsPerHistoricalRoot + gid := generic.GetGeneralizedIndexForListElement( + gloas.GetGeneralizedIndexForHistoricalSummaries(), + generic.BeaconStateHistoricalSummariesMaxLength, + arrayIndex, + ) + proof, err := tree.Prove(int(gid)) + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, fmt.Errorf("could not get proof for historical summary: %w", err) + } + historicalSummaryProof := proof.Hashes + + blockHeaderProof, err := gloasState.BlockHeaderProof() + if err != nil { + return megapool.FinalBalanceProof{}, 0, nil, err + } + + finalProof = append(finalProof, withdrawalProof...) + finalProof = append(finalProof, summaryStateRootProof...) + finalProof = append(finalProof, historicalSummaryProof...) + finalProof = append(finalProof, blockHeaderProof...) + } + + // Convert [][]byte to [][32]byte + response.Witnesses = ConvertToFixedSize(finalProof) + + return response, finalizedSlot, beaconState, nil +} + +// verifyExpectedWithdrawal checks that the withdrawal found on the execution +// layer matches the entry the beacon state committed to at the same position +// in payload_expected_withdrawals. +func verifyExpectedWithdrawal(state *gloas.BeaconState, indexInWithdrawalsArray int, withdrawal *generic.Withdrawal) error { + if indexInWithdrawalsArray >= len(state.PayloadExpectedWithdrawals) { + return fmt.Errorf("withdrawal index %d out of bounds: state at slot %d has %d expected withdrawals", indexInWithdrawalsArray, state.Slot, len(state.PayloadExpectedWithdrawals)) + } + expected := state.PayloadExpectedWithdrawals[indexInWithdrawalsArray] + if expected.Index != withdrawal.Index || + expected.ValidatorIndex != withdrawal.ValidatorIndex || + expected.Address != withdrawal.Address || + expected.Amount != withdrawal.Amount { + return fmt.Errorf("withdrawal %d for validator %d found on the execution layer does not match the expected withdrawal committed to the state at slot %d", withdrawal.Index, withdrawal.ValidatorIndex, state.Slot) + } + return nil +} + +// FindGloasWithdrawalSlotAndArrayPosition locates the withdrawal for the given +// validator index by scanning execution-layer blocks, which still carry the +// withdrawals list in Gloas, and maps the execution block back to the consensus +// slot whose beacon state committed to its payload's withdrawals. Returns the +// consensus slot, the withdrawal's position in the payload's withdrawals list +// (identical to its position in the state's payload_expected_withdrawals) and +// the withdrawal itself. +func FindGloasWithdrawalSlotAndArrayPosition(slot uint64, validatorIndex uint64, ec *ExecutionClientManager, eth2Config beacon.Eth2Config) (uint64, int, *generic.Withdrawal, error) { + ctx := context.Background() + + // Binary search the EL for the first block at or after the start slot. + startTime := uint64(eth2Config.GetSlotTime(slot).Unix()) + endTime := uint64(eth2Config.GetSlotTime(slot + MAX_WITHDRAWAL_SLOT_DISTANCE).Unix()) + blockNumber, err := findExecutionBlockByTime(ec, startTime) + if err != nil { + return 0, 0, nil, err + } + latest, err := ec.BlockNumber(ctx) + if err != nil { + return 0, 0, nil, err + } + + for ; blockNumber <= latest; blockNumber++ { + block, err := ec.BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber)) + if err != nil { + return 0, 0, nil, err + } + blockTime := block.Time() + if blockTime < startTime { + continue + } + if blockTime > endTime { + break + } + for i, elWithdrawal := range block.Withdrawals() { + if elWithdrawal.Validator != validatorIndex { + continue + } + withdrawal := &generic.Withdrawal{ + Index: elWithdrawal.Index, + ValidatorIndex: elWithdrawal.Validator, + Address: elWithdrawal.Address, + Amount: elWithdrawal.Amount, + } + withdrawalSlot := slotOfExecutionBlock(block, eth2Config) + return withdrawalSlot, i, withdrawal, nil + } + } + return 0, 0, nil, fmt.Errorf("no withdrawal found for validator index %d within %d slots of slot %d", validatorIndex, MAX_WITHDRAWAL_SLOT_DISTANCE, slot) +} + +// slotOfExecutionBlock returns the consensus slot an execution block belongs to. +func slotOfExecutionBlock(block *ethtypes.Block, eth2Config beacon.Eth2Config) uint64 { + if slotNumber := block.Header().SlotNumber; slotNumber != nil { + return *slotNumber + } + return eth2Config.FirstSlotAtLeast(int64(block.Time())) +} + +// findExecutionBlockByTime returns the number of the first execution block with +// a timestamp greater than or equal to the given time. +func findExecutionBlockByTime(ec *ExecutionClientManager, timestamp uint64) (uint64, error) { + ctx := context.Background() + latest, err := ec.BlockNumber(ctx) + if err != nil { + return 0, err + } + + low, high := uint64(0), latest + for low < high { + mid := (low + high) / 2 + header, err := ec.HeaderByNumber(ctx, new(big.Int).SetUint64(mid)) + if err != nil { + return 0, err + } + if header.Time >= timestamp { + high = mid + } else { + low = mid + 1 + } + } + return low, nil +} + func ConvertWithdrawalAmount(amount uint64) *big.Int { amountBigInt := big.NewInt(int64(amount)) diff --git a/shared/services/rewards/execution-client.go b/shared/services/rewards/execution-client.go index 92fff23ad..1d6661829 100644 --- a/shared/services/rewards/execution-client.go +++ b/shared/services/rewards/execution-client.go @@ -43,6 +43,10 @@ func (client *defaultRewardsExecutionClient) HeaderByNumber(ctx context.Context, return client.RocketPool.Client.HeaderByNumber(ctx, block) } +func (client *defaultRewardsExecutionClient) HeaderByHash(ctx context.Context, hash common.Hash) (*ethtypes.Header, error) { + return client.RocketPool.Client.HeaderByHash(ctx, hash) +} + func (client *defaultRewardsExecutionClient) GetRewardsEvent(index uint64, rocketRewardsPoolAddresses []common.Address, opts *bind.CallOpts) (bool, rewards.RewardsEvent, error) { found, rewardsEvent, err := rewards.GetRewardsEvent(client.RocketPool, index, rocketRewardsPoolAddresses, opts) if err == nil && found { diff --git a/shared/services/rewards/generator-impl-v11.go b/shared/services/rewards/generator-impl-v11.go index c2933089c..42c2d4e40 100644 --- a/shared/services/rewards/generator-impl-v11.go +++ b/shared/services/rewards/generator-impl-v11.go @@ -1749,6 +1749,7 @@ func (r *treeGeneratorImpl_v11) getBlocksAndTimesForInterval(previousIntervalEve // Get the first block that isn't missing var elBlockNumber uint64 + var hasElBlock bool for { beaconBlock, exists, err := r.bc.GetBeaconBlock(fmt.Sprint(r.rewardsFile.ConsensusStartBlock)) if err != nil { @@ -1758,13 +1759,17 @@ func (r *treeGeneratorImpl_v11) getBlocksAndTimesForInterval(previousIntervalEve r.rewardsFile.ConsensusStartBlock++ r.performanceFile.ConsensusStartBlock++ } else { - elBlockNumber = beaconBlock.ExecutionBlockNumber + // Gloas blocks only commit to the EL block hash, so the number has to be resolved + elBlockNumber, hasElBlock, err = beacon.ResolveExecutionBlockNumber(context.Background(), r.rp, beaconBlock) + if err != nil { + return nil, err + } break } } var startElHeader *types.Header - if elBlockNumber == 0 { + if !hasElBlock { // We are pre-merge, so get the first block after the one from the previous interval r.rewardsFile.ExecutionStartBlock = previousIntervalEvent.ExecutionBlock.Uint64() + 1 r.performanceFile.ExecutionStartBlock = r.rewardsFile.ExecutionStartBlock diff --git a/shared/services/rewards/generator.go b/shared/services/rewards/generator.go index 9fabf38f8..2b2e2ada8 100644 --- a/shared/services/rewards/generator.go +++ b/shared/services/rewards/generator.go @@ -53,7 +53,7 @@ const ( MainnetV10Interval uint64 = 30 MainnetV11Interval uint64 = 46 // Devnet intervals - DevnetV11Interval uint64 = 7 + DevnetV11Interval uint64 = 0 // Testnet intervals TestnetV10Interval uint64 = 0 diff --git a/shared/services/rewards/test/rocketpool.go b/shared/services/rewards/test/rocketpool.go index 4058e6fc8..f93f7fb19 100644 --- a/shared/services/rewards/test/rocketpool.go +++ b/shared/services/rewards/test/rocketpool.go @@ -6,6 +6,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -35,6 +36,7 @@ type MockRocketPool struct { t *testing.T rewardSnapshotEvents map[uint64]rewards.RewardsEvent headers map[uint64]*types.Header + headersByHash map[common.Hash]*types.Header } func NewMockRocketPool(t *testing.T, index uint64) *MockRocketPool { @@ -59,6 +61,21 @@ func (mock *MockRocketPool) SetHeaderByNumber(number *big.Int, header *types.Hea mock.headers[number.Uint64()] = header } +// Used to resolve Gloas payload bids, which only commit to the EL block hash. +func (mock *MockRocketPool) HeaderByHash(_ context.Context, hash common.Hash) (*types.Header, error) { + if header, ok := mock.headersByHash[hash]; ok { + return header, nil + } + return nil, ethereum.NotFound +} + +func (mock *MockRocketPool) SetHeaderByHash(hash common.Hash, header *types.Header) { + if mock.headersByHash == nil { + mock.headersByHash = make(map[common.Hash]*types.Header) + } + mock.headersByHash[hash] = header +} + func (mock *MockRocketPool) GetRewardsEvent(index uint64, _ []common.Address, opts *bind.CallOpts) (bool, rewards.RewardsEvent, error) { if event, ok := mock.rewardSnapshotEvents[index]; ok { diff --git a/shared/services/rewards/types.go b/shared/services/rewards/types.go index a934b54f2..968d0629b 100644 --- a/shared/services/rewards/types.go +++ b/shared/services/rewards/types.go @@ -41,6 +41,7 @@ const ( type RewardsExecutionClient interface { GetNetworkEnabled(networkId *big.Int, opts *bind.CallOpts) (bool, error) HeaderByNumber(context.Context, *big.Int) (*ethtypes.Header, error) + HeaderByHash(context.Context, common.Hash) (*ethtypes.Header, error) GetRewardsEvent(index uint64, rocketRewardsPoolAddresses []common.Address, opts *bind.CallOpts) (bool, rewards.RewardsEvent, error) GetRewardSnapshotEvent(previousRewardsPoolAddresses []common.Address, interval uint64, opts *bind.CallOpts) (rewards.RewardsEvent, error) GetRewardIndex(opts *bind.CallOpts) (*big.Int, error) diff --git a/shared/services/state/manager.go b/shared/services/state/manager.go index 0998c3b70..014d46e54 100644 --- a/shared/services/state/manager.go +++ b/shared/services/state/manager.go @@ -125,7 +125,7 @@ func (m *NetworkStateManager) getHeadSlot() (uint64, error) { return targetSlot, nil } -// Gets the target Beacon block, or if it was missing, the first one under it that wasn't missing +// Gets the target Beacon block, or if it was missing, the first one under it that wasn't missing. func (m *NetworkStateManager) getLatestProposedBeaconBlock(targetSlot uint64) (beacon.BeaconBlock, error) { for { // Try to get the current block @@ -138,9 +138,25 @@ func (m *NetworkStateManager) getLatestProposedBeaconBlock(targetSlot uint64) (b if !exists { m.logLine("Slot %d was missing, trying the previous one...", targetSlot) targetSlot-- - } else { - return block, nil + continue } + + // Gloas blocks only carry the payload bid's block hash, so resolve the number here + elBlockNumber, found, err := beacon.ResolveExecutionBlockNumber(context.Background(), m.rp.Client, block) + if err != nil { + return beacon.BeaconBlock{}, err + } + + // The block bid for a payload that was never revealed, so it has no EL block; try the + // previous slot. + if !found && block.HasExecutionPayload { + m.logLine("Slot %d bid for a payload that was never revealed, trying the previous one...", targetSlot) + targetSlot-- + continue + } + + block.ExecutionBlockNumber = elBlockNumber + return block, nil } } diff --git a/shared/services/state/network-state.go b/shared/services/state/network-state.go index 067fb99f9..eeaa60142 100644 --- a/shared/services/state/network-state.go +++ b/shared/services/state/network-state.go @@ -1,6 +1,7 @@ package state import ( + "context" "encoding/json" "fmt" "math/big" @@ -197,8 +198,14 @@ func (m *NetworkStateManager) createNetworkState(slotNumber uint64, nodeAddresse return nil, fmt.Errorf("slot %d did not have a Beacon block", slotNumber) } - // Get the corresponding block on the EL - elBlockNumber := beaconBlock.ExecutionBlockNumber + // Get the corresponding block on the EL. + elBlockNumber, found, err := beacon.ResolveExecutionBlockNumber(context.Background(), m.rp.Client, beaconBlock) + if err != nil { + return nil, err + } + if !found && beaconBlock.HasExecutionPayload { + return nil, fmt.Errorf("slot %d has an execution payload association but no resolvable EL block number", slotNumber) + } opts := &bind.CallOpts{ BlockNumber: big.NewInt(0).SetUint64(elBlockNumber), } diff --git a/shared/types/api/megapool.go b/shared/types/api/megapool.go index ad936c60f..a4bee2a2f 100644 --- a/shared/types/api/megapool.go +++ b/shared/types/api/megapool.go @@ -20,6 +20,8 @@ type MegapoolStatusResponse struct { Megapool MegapoolDetails `json:"megapoolDetails"` LatestDelegate common.Address `json:"latestDelegate"` BeaconHead beacon.BeaconHead `json:"beaconHead"` + // ShardCommitteePeriod is the number of epochs after activation before voluntary exit is allowed + ShardCommitteePeriod uint64 `json:"shardCommitteePeriod"` } type MegapoolDetails struct { diff --git a/shared/types/api/node.go b/shared/types/api/node.go index 143e0296d..dbc536ca1 100644 --- a/shared/types/api/node.go +++ b/shared/types/api/node.go @@ -829,11 +829,14 @@ type ExitValidatorResponse struct { } type CanNotifyValidatorExitResponse struct { - Status string `json:"status"` - Error string `json:"error"` - CanExit bool `json:"canExit"` - InvalidStatus bool `json:"invalidStatus"` - GasLimits gaslimit.Limits `json:"gasLimits"` + Status string `json:"status"` + Error string `json:"error"` + CanExit bool `json:"canExit"` + InvalidStatus bool `json:"invalidStatus"` + AlreadyExiting bool `json:"alreadyExiting"` + AlreadyExited bool `json:"alreadyExited"` + ExitNotFinalized bool `json:"exitNotFinalized"` + GasLimits gaslimit.Limits `json:"gasLimits"` } type NotifyValidatorExitResponse struct { Status string `json:"status"` diff --git a/shared/types/eth2/fork/deneb/state_deneb.go b/shared/types/eth2/fork/deneb/state_deneb.go index 8dd327f38..48c9e34b2 100644 --- a/shared/types/eth2/fork/deneb/state_deneb.go +++ b/shared/types/eth2/fork/deneb/state_deneb.go @@ -7,7 +7,6 @@ import ( "reflect" "sync/atomic" - "github.com/rocket-pool/smartnode/shared/math" "github.com/rocket-pool/smartnode/shared/types/eth2/generic" ) @@ -60,9 +59,9 @@ func getStateChunkSize() uint64 { } func GetGeneralizedIndexForValidators() uint64 { - // There's 28 fields, so rounding up to the next power of two is 32, a left-aligned node - // BeaconStateValidatorsIndex is the 11th field, so its generalized index is 32 + 11 = 43 - return math.GetPowerOfTwoCeil(getStateChunkSize()) + generic.BeaconStateValidatorsIndex + // Classic SSZ Container field gindex (pre-Gloas). Field count rounded up to + // the next power of two; validators is field index 11. + return generic.ContainerFieldGindex(getStateChunkSize(), generic.BeaconStateValidatorsIndex) } func (state *BeaconState) validatorStateProof(index uint64) ([][]byte, error) { diff --git a/shared/types/eth2/fork/electra/state_electra.go b/shared/types/eth2/fork/electra/state_electra.go index 55e649f4e..d32b8639e 100644 --- a/shared/types/eth2/fork/electra/state_electra.go +++ b/shared/types/eth2/fork/electra/state_electra.go @@ -7,7 +7,6 @@ import ( "reflect" "sync/atomic" - "github.com/rocket-pool/smartnode/shared/math" "github.com/rocket-pool/smartnode/shared/types/eth2/generic" ) @@ -71,15 +70,14 @@ func getStateChunkSize() uint64 { } func GetGeneralizedIndexForValidators() uint64 { - // There's 28 fields, so rounding up to the next power of two is 32, a left-aligned node - // BeaconStateValidatorsIndex is the 11th field, so its generalized index is 32 + 11 = 43 - return math.GetPowerOfTwoCeil(getStateChunkSize()) + generic.BeaconStateValidatorsIndex + // Classic SSZ Container field gindex (pre-Gloas). Field count rounded up to + // the next power of two; validators is field index 11. + return generic.ContainerFieldGindex(getStateChunkSize(), generic.BeaconStateValidatorsIndex) } func GetGeneralizedIndexForSlot() uint64 { - // There's 28 fields, so rounding up to the next power of two is 32, a left-aligned node - // BeaconStateValidatorsIndex is the 2nd field, so its generalized index is 32 + 2 = 34 - return math.GetPowerOfTwoCeil(getStateChunkSize()) + generic.BeaconStateSlotIndex + // Classic SSZ Container field gindex (pre-Gloas); slot is field index 2. + return generic.ContainerFieldGindex(getStateChunkSize(), generic.BeaconStateSlotIndex) } // ValidatorAndSlotProof produces both the validator proof and the slot proof diff --git a/shared/types/eth2/fork/fulu/state_fulu.go b/shared/types/eth2/fork/fulu/state_fulu.go index e40230986..258708bf5 100644 --- a/shared/types/eth2/fork/fulu/state_fulu.go +++ b/shared/types/eth2/fork/fulu/state_fulu.go @@ -7,7 +7,6 @@ import ( "reflect" "sync/atomic" - "github.com/rocket-pool/smartnode/shared/math" "github.com/rocket-pool/smartnode/shared/types/eth2/generic" ) @@ -74,15 +73,14 @@ func getStateChunkSize() uint64 { } func GetGeneralizedIndexForValidators() uint64 { - // There's 28 fields, so rounding up to the next power of two is 32, a left-aligned node - // BeaconStateValidatorsIndex is the 11th field, so its generalized index is 32 + 11 = 43 - return math.GetPowerOfTwoCeil(getStateChunkSize()) + generic.BeaconStateValidatorsIndex + // Classic SSZ Container field gindex (pre-Gloas). Field count rounded up to + // the next power of two; validators is field index 11. + return generic.ContainerFieldGindex(getStateChunkSize(), generic.BeaconStateValidatorsIndex) } func GetGeneralizedIndexForSlot() uint64 { - // There's 28 fields, so rounding up to the next power of two is 32, a left-aligned node - // BeaconStateValidatorsIndex is the 2nd field, so its generalized index is 32 + 2 = 34 - return math.GetPowerOfTwoCeil(getStateChunkSize()) + generic.BeaconStateSlotIndex + // Classic SSZ Container field gindex (pre-Gloas); slot is field index 2. + return generic.ContainerFieldGindex(getStateChunkSize(), generic.BeaconStateSlotIndex) } // ValidatorAndSlotProof produces both the validator proof and the slot proof diff --git a/shared/types/eth2/fork/gloas/block_gloas.go b/shared/types/eth2/fork/gloas/block_gloas.go new file mode 100644 index 000000000..202858a9e --- /dev/null +++ b/shared/types/eth2/fork/gloas/block_gloas.go @@ -0,0 +1,172 @@ +package gloas + +import ( + "errors" + + "github.com/prysmaticlabs/go-bitfield" + + "github.com/rocket-pool/smartnode/shared/types/eth2/generic" +) + +// Important indices for proof generation: +// The Gloas BeaconBlockBody has 13 fields. Pre-EIP-7688 proofs used power-of-two +// body layout (ceil 16). Under EIP-7688 BeaconBlockBody is a ProgressiveContainer. +const BeaconBlockBodyChunksCeil uint64 = 16 + +// In Gloas (EIP-7732), the execution payload is no longer part of the beacon block. +// It is distributed separately in a SignedExecutionPayloadEnvelope, and the block body +// only carries a SignedExecutionPayloadBid. Withdrawals can no longer be proven +// against the block root; they are committed to in the state's payload_expected_withdrawals. +func (b *SignedBeaconBlock) ProveWithdrawal(indexInWithdrawalsArray uint64) ([][]byte, error) { + return nil, errors.New("gloas blocks do not contain the execution payload; withdrawals must be proven against the beacon state's payload_expected_withdrawals field") +} + +// BeaconBlock remains a normal Container (not converted by EIP-7688). +type BeaconBlock struct { + Slot uint64 `json:"slot"` + ProposerIndex uint64 `json:"proposer_index"` + ParentRoot [32]byte `json:"parent_root" ssz-size:"32"` + StateRoot [32]byte `json:"state_root" ssz-size:"32"` + Body *BeaconBlockBody `json:"body"` +} + +// SignedBeaconBlock remains a normal Container (not converted by EIP-7688). +type SignedBeaconBlock struct { + Block *BeaconBlock `json:"message"` + Signature []byte `json:"signature" ssz-size:"96"` +} + +// Modified in Gloas (EIP-7732/EIP-7688): +// - Removed ExecutionPayload, BlobKzgCommitments and ExecutionRequests (moved to the ExecutionPayloadEnvelope) +// - Added SignedExecutionPayloadBid, PayloadAttestations and ParentExecutionRequests +// - EIP-7688: ProgressiveContainer + ProgressiveList on operation lists +type BeaconBlockBody struct { + RandaoReveal []byte `json:"randao_reveal" ssz-size:"96" ssz-index:"0"` + Eth1Data *generic.Eth1Data `json:"eth1_data" ssz-index:"1"` + Graffiti [32]byte `json:"graffiti" ssz-size:"32" ssz-index:"2"` + ProposerSlashings []*generic.ProposerSlashing `json:"proposer_slashings" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"3"` + AttesterSlashings []*AttesterSlashing `json:"attester_slashings" ssz-type:"progressive-list" ssz-max:"1" ssz-index:"4"` + Attestations []*Attestation `json:"attestations" ssz-type:"progressive-list" ssz-max:"8" ssz-index:"5"` + Deposits []*generic.Deposit `json:"deposits" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"6"` + VoluntaryExits []*generic.SignedVoluntaryExit `json:"voluntary_exits" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"7"` + SyncAggregate *generic.SyncAggregate `json:"sync_aggregate" ssz-index:"8"` + BlsToExecutionChanges []*generic.SignedBLSToExecutionChange `json:"bls_to_execution_changes" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"9"` + SignedExecutionPayloadBid *SignedExecutionPayloadBid `json:"signed_execution_payload_bid" ssz-index:"10"` + PayloadAttestations []*PayloadAttestation `json:"payload_attestations" ssz-type:"progressive-list" ssz-max:"4" ssz-index:"11"` + ParentExecutionRequests *ExecutionRequests `json:"parent_execution_requests" ssz-index:"12"` +} + +// Modified in Gloas:EIP-7688 — ProgressiveContainer with ProgressiveBitlist aggregation_bits. +type Attestation struct { + AggregationBits bitfield.Bitlist `json:"aggregation_bits" ssz-type:"progressive-bitlist" ssz-max:"131072" ssz-index:"0"` + Data *generic.AttestationData `json:"data" ssz-index:"1"` + Signature [96]byte `json:"signature" ssz-size:"96" ssz-index:"2"` + CommitteeBits []byte `json:"committee_bits" ssz-size:"8" ssz-index:"3"` +} + +// New in Gloas (EIP-7732). ProgressiveContainer (EIP-7688). +type ExecutionPayloadBid struct { + ParentBlockHash [32]byte `json:"parent_block_hash" ssz-size:"32" ssz-index:"0"` + ParentBlockRoot [32]byte `json:"parent_block_root" ssz-size:"32" ssz-index:"1"` + BlockHash [32]byte `json:"block_hash" ssz-size:"32" ssz-index:"2"` + PrevRandao [32]byte `json:"prev_randao" ssz-size:"32" ssz-index:"3"` + FeeRecipient [20]byte `json:"fee_recipient" ssz-size:"20" ssz-index:"4"` + GasLimit uint64 `json:"gas_limit" ssz-index:"5"` + BuilderIndex uint64 `json:"builder_index" ssz-index:"6"` + Slot uint64 `json:"slot" ssz-index:"7"` + Value uint64 `json:"value" ssz-index:"8"` + ExecutionPayment uint64 `json:"execution_payment" ssz-index:"9"` + BlobKzgCommitments [][48]byte `json:"blob_kzg_commitments" ssz-type:"progressive-list" ssz-max:"4096" ssz-size:"?,48" ssz-index:"10"` + ExecutionRequestsRoot [32]byte `json:"execution_requests_root" ssz-size:"32" ssz-index:"11"` +} + +// New in Gloas (EIP-7732). Immutable container. +type SignedExecutionPayloadBid struct { + Message *ExecutionPayloadBid `json:"message"` + Signature [96]byte `json:"signature" ssz-size:"96"` +} + +// New in Gloas (EIP-7732). Immutable container. +type PayloadAttestationData struct { + BeaconBlockRoot [32]byte `json:"beacon_block_root" ssz-size:"32"` + Slot uint64 `json:"slot"` + PayloadPresent bool `json:"payload_present"` + BlobDataAvailable bool `json:"blob_data_available"` +} + +// New in Gloas (EIP-7732). ProgressiveContainer. +// AggregationBits is a Bitvector[PTC_SIZE] where PTC_SIZE = 512 (64 bytes). +type PayloadAttestation struct { + AggregationBits []byte `json:"aggregation_bits" ssz-size:"64" ssz-index:"0"` + Data *PayloadAttestationData `json:"data" ssz-index:"1"` + Signature [96]byte `json:"signature" ssz-size:"96" ssz-index:"2"` +} + +// Modified in Gloas (EIP-8282/EIP-7688): ProgressiveContainer with ProgressiveList fields; +// added BuilderDeposits and BuilderExits. +type ExecutionRequests struct { + Deposits []*DepositRequest `json:"deposits" ssz-type:"progressive-list" ssz-max:"8192" ssz-index:"0"` + Withdrawals []*WithdrawalRequest `json:"withdrawals" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"1"` + Consolidations []*ConsolidationRequest `json:"consolidations" ssz-type:"progressive-list" ssz-max:"2" ssz-index:"2"` + BuilderDeposits []*BuilderDepositRequest `json:"builder_deposits" ssz-type:"progressive-list" ssz-max:"64" ssz-index:"3"` + BuilderExits []*BuilderExitRequest `json:"builder_exits" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"4"` +} + +// Immutable container. +type DepositRequest struct { + Pubkey []byte `json:"pubkey" ssz-size:"48"` + WithdrawalCredentials []byte `json:"withdrawal_credentials" ssz-size:"32"` + Amount uint64 `json:"amount"` + Signature []byte `json:"signature" ssz-size:"96"` + Index uint64 `json:"index"` +} + +// Immutable container. +type WithdrawalRequest struct { + SourceAddress []byte `json:"source_address" ssz-size:"20"` + ValidatorPubkey []byte `json:"validator_pubkey" ssz-size:"48"` + Amount uint64 `json:"amount"` +} + +// Immutable container. +type ConsolidationRequest struct { + SourceAddress []byte `json:"source_address" ssz-size:"20"` + SourcePubkey []byte `json:"source_pubkey" ssz-size:"48"` + TargetPubkey []byte `json:"target_pubkey" ssz-size:"48"` +} + +// New in Gloas (EIP-8282). Immutable container. +type BuilderDepositRequest struct { + Pubkey []byte `json:"pubkey" ssz-size:"48"` + WithdrawalCredentials []byte `json:"withdrawal_credentials" ssz-size:"32"` + Amount uint64 `json:"amount"` + Signature []byte `json:"signature" ssz-size:"96"` +} + +// New in Gloas (EIP-8282). Immutable container. +type BuilderExitRequest struct { + SourceAddress []byte `json:"source_address" ssz-size:"20"` + Pubkey []byte `json:"pubkey" ssz-size:"48"` +} + +// Immutable container (AttesterSlashing itself is listed as immutable in EIP-7688). +type AttesterSlashing struct { + Attestation1 *IndexedAttestation `json:"attestation_1"` + Attestation2 *IndexedAttestation `json:"attestation_2"` +} + +// Modified in Gloas:EIP-7688 — ProgressiveContainer with ProgressiveList attesting_indices. +type IndexedAttestation struct { + AttestingIndices []uint64 `json:"attesting_indices" ssz-type:"progressive-list" ssz-max:"131072" ssz-index:"0"` + Data *generic.AttestationData `json:"data" ssz-index:"1"` + Signature []byte `json:"signature" ssz-size:"96" ssz-index:"2"` +} + +// In Gloas the execution payload is never part of the block itself. +func (b *SignedBeaconBlock) HasExecutionPayload() bool { + return false +} + +func (b *SignedBeaconBlock) Withdrawals() []*generic.Withdrawal { + return nil +} diff --git a/shared/types/eth2/fork/gloas/gloas_generated.go b/shared/types/eth2/fork/gloas/gloas_generated.go new file mode 100644 index 000000000..d95321842 --- /dev/null +++ b/shared/types/eth2/fork/gloas/gloas_generated.go @@ -0,0 +1,9489 @@ +// Code generated by dynamic-ssz. DO NOT EDIT. +// Hash: bb0b21af0306c2dcc0244a5fa8e83a72d41791c1dc78c28370071125eb14b649 +// Version: v1.3.2 (https://github.com/pk910/dynamic-ssz) +package gloas + +import ( + "encoding/binary" + "math/bits" + + "github.com/pk910/dynamic-ssz/hasher" + "github.com/pk910/dynamic-ssz/sszutils" + go_bitfield "github.com/prysmaticlabs/go-bitfield" + "github.com/rocket-pool/smartnode/shared/types/eth2/generic" +) + +var _ = sszutils.ErrListTooBig + +var _ = sszutils.Annotate[BeaconState](`ssz-static:"false"`) +var _ = sszutils.Annotate[SignedBeaconBlock](`ssz-static:"false"`) +var _ = sszutils.Annotate[BeaconBlock](`ssz-static:"false"`) +var _ = sszutils.Annotate[BeaconBlockBody](`ssz-static:"false"`) +var _ = sszutils.Annotate[Builder](`ssz-static:"true"`) +var _ = sszutils.Annotate[BuilderPendingWithdrawal](`ssz-static:"true"`) +var _ = sszutils.Annotate[BuilderPendingPayment](`ssz-static:"true"`) +var _ = sszutils.Annotate[Attestation](`ssz-static:"false"`) +var _ = sszutils.Annotate[ExecutionPayloadBid](`ssz-static:"false"`) +var _ = sszutils.Annotate[SignedExecutionPayloadBid](`ssz-static:"false"`) +var _ = sszutils.Annotate[PayloadAttestationData](`ssz-static:"true"`) +var _ = sszutils.Annotate[PayloadAttestation](`ssz-static:"true"`) +var _ = sszutils.Annotate[ExecutionRequests](`ssz-static:"false"`) +var _ = sszutils.Annotate[DepositRequest](`ssz-static:"true"`) +var _ = sszutils.Annotate[WithdrawalRequest](`ssz-static:"true"`) +var _ = sszutils.Annotate[ConsolidationRequest](`ssz-static:"true"`) +var _ = sszutils.Annotate[BuilderDepositRequest](`ssz-static:"true"`) +var _ = sszutils.Annotate[BuilderExitRequest](`ssz-static:"true"`) +var _ = sszutils.Annotate[AttesterSlashing](`ssz-static:"false"`) +var _ = sszutils.Annotate[IndexedAttestation](`ssz-static:"false"`) + +// MarshalSSZDyn marshals the *BeaconState to SSZ-encoded bytes using dynamic specifications. +func (t *BeaconState) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + zeroBytes := sszutils.ZeroBytes() + if t == nil { + t = new(BeaconState) + } + dstlen := len(dst) + { // Static Field #0 'GenesisTime' + dst = binary.LittleEndian.AppendUint64(dst, t.GenesisTime) + } + { // Static Field #1 'GenesisValidatorsRoot' + vlen := len(t.GenesisValidatorsRoot) + if vlen > 32 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "GenesisValidatorsRoot") + } + dst = append(dst, t.GenesisValidatorsRoot[:vlen]...) + if vlen < 32 { + dst = sszutils.AppendZeroPadding(dst, (32-vlen)*1) + } + } + { // Static Field #2 'Slot' + dst = binary.LittleEndian.AppendUint64(dst, t.Slot) + } + { // Static Field #3 'Fork' + t := t.Fork + if t == nil { + t = new(generic.Fork) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Fork") + } + } + { // Static Field #4 'LatestBlockHeader' + t := t.LatestBlockHeader + if t == nil { + t = new(generic.BeaconBlockHeader) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "LatestBlockHeader") + } + } + { // Static Field #5 'BlockRoots' + t := &t.BlockRoots + dst = sszutils.MarshalFixedBytesSlice(dst, t[:8192]) + } + { // Static Field #6 'StateRoots' + t := &t.StateRoots + dst = sszutils.MarshalFixedBytesSlice(dst, t[:8192]) + } + // Offset Field #7 'HistoricalRoots' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #8 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Eth1Data") + } + } + // Offset Field #9 'Eth1DataVotes' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #10 'Eth1DepositIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.Eth1DepositIndex) + } + // Offset Field #11 'Validators' + // Offset Field #12 'Balances' + dst = append(dst, 0, 0, 0, 0, 0, 0, 0, 0) + { // Static Field #13 'RandaoMixes' + t := t.RandaoMixes + vlen := len(t) + if vlen > 65536 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 65536), "RandaoMixes") + } + for idx1 := range vlen { + vlen := len(t[idx1]) + if vlen > 32 { + return nil, sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "RandaoMixes[%d]", idx1) + } + dst = append(dst, t[idx1][:vlen]...) + if vlen < 32 { + dst = sszutils.AppendZeroPadding(dst, (32-vlen)*1) + } + } + if vlen < 65536 { + dst = sszutils.AppendZeroPadding(dst, (65536-vlen)*32) + } + } + { // Static Field #14 'Slashings' + t := t.Slashings + vlen := len(t) + if vlen > 8192 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8192), "Slashings") + } + dst = sszutils.MarshalUint64Slice(dst, t[:vlen]) + if vlen < 8192 { + dst = sszutils.AppendZeroPadding(dst, (8192-vlen)*8) + } + } + // Offset Field #15 'PreviousEpochParticipation' + // Offset Field #16 'CurrentEpochParticipation' + dst = append(dst, 0, 0, 0, 0, 0, 0, 0, 0) + { // Static Field #17 'JustificationBits' + dst = append(dst, t.JustificationBits[:1]...) + } + { // Static Field #18 'PreviousJustifiedCheckpoint' + t := t.PreviousJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "PreviousJustifiedCheckpoint") + } + } + { // Static Field #19 'CurrentJustifiedCheckpoint' + t := t.CurrentJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "CurrentJustifiedCheckpoint") + } + } + { // Static Field #20 'FinalizedCheckpoint' + t := t.FinalizedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "FinalizedCheckpoint") + } + } + // Offset Field #21 'InactivityScores' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #22 'CurrentSyncCommittee' + t := t.CurrentSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "CurrentSyncCommittee") + } + } + { // Static Field #23 'NextSyncCommittee' + t := t.NextSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "NextSyncCommittee") + } + } + { // Static Field #24 'LatestBlockHash' + dst = append(dst, t.LatestBlockHash[:32]...) + } + { // Static Field #25 'NextWithdrawalIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.NextWithdrawalIndex) + } + { // Static Field #26 'NextWithdrawalValidatorIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.NextWithdrawalValidatorIndex) + } + // Offset Field #27 'HistoricalSummaries' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #28 'DepositRequestsStartIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.DepositRequestsStartIndex) + } + { // Static Field #29 'DepositBalanceToConsume' + dst = binary.LittleEndian.AppendUint64(dst, t.DepositBalanceToConsume) + } + { // Static Field #30 'ExitBalanceToConsume' + dst = binary.LittleEndian.AppendUint64(dst, t.ExitBalanceToConsume) + } + { // Static Field #31 'EarliestExitEpoch' + dst = binary.LittleEndian.AppendUint64(dst, t.EarliestExitEpoch) + } + { // Static Field #32 'ConsolidationBalanceToConsume' + dst = binary.LittleEndian.AppendUint64(dst, t.ConsolidationBalanceToConsume) + } + { // Static Field #33 'EarliestConsolidationEpoch' + dst = binary.LittleEndian.AppendUint64(dst, t.EarliestConsolidationEpoch) + } + // Offset Field #34 'PendingDeposits' + // Offset Field #35 'PendingPartialWithdrawals' + // Offset Field #36 'PendingConsolidations' + dst = append(dst, zeroBytes[:12]...) + { // Static Field #37 'ProposerLookahead' + t := t.ProposerLookahead + vlen := len(t) + if vlen > 64 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "ProposerLookahead") + } + dst = sszutils.MarshalUint64Slice(dst, t[:vlen]) + if vlen < 64 { + dst = sszutils.AppendZeroPadding(dst, (64-vlen)*8) + } + } + // Offset Field #38 'Builders' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #39 'NextWithdrawalBuilderIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.NextWithdrawalBuilderIndex) + } + { // Static Field #40 'ExecutionPayloadAvailability' + vlen := len(t.ExecutionPayloadAvailability) + if vlen > 1024 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 1024), "ExecutionPayloadAvailability") + } + dst = append(dst, t.ExecutionPayloadAvailability[:vlen]...) + if vlen < 1024 { + dst = sszutils.AppendZeroPadding(dst, (1024-vlen)*1) + } + } + { // Static Field #41 'BuilderPendingPayments' + t := &t.BuilderPendingPayments + for idx1 := range 64 { + t := t[idx1] + if t == nil { + t = new(BuilderPendingPayment) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "BuilderPendingPayments[%d]", idx1) + } + } + } + // Offset Field #42 'BuilderPendingWithdrawals' + // Offset Field #43 'LatestExecutionPayloadBid' + // Offset Field #44 'PayloadExpectedWithdrawals' + dst = append(dst, zeroBytes[:12]...) + { // Static Field #45 'PtcWindow' + t := &t.PtcWindow + for idx1 := range 96 { + t := &t[idx1] + dst = sszutils.MarshalUint64Slice(dst, t[:512]) + } + } + { // Dynamic Field #7 'HistoricalRoots' + binary.LittleEndian.PutUint32(dst[dstlen+524464:], uint32(len(dst)-dstlen)) + t := t.HistoricalRoots + vlen := len(t) + if vlen > 16777216 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalRoots") + } + for idx1 := range vlen { + vlen := len(t[idx1]) + if vlen > 32 { + return nil, sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "HistoricalRoots[%d]", idx1) + } + dst = append(dst, t[idx1][:vlen]...) + if vlen < 32 { + dst = sszutils.AppendZeroPadding(dst, (32-vlen)*1) + } + } + } + { // Dynamic Field #9 'Eth1DataVotes' + binary.LittleEndian.PutUint32(dst[dstlen+524540:], uint32(len(dst)-dstlen)) + t := t.Eth1DataVotes + vlen := len(t) + if vlen > 2048 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2048), "Eth1DataVotes") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Eth1Data) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Eth1DataVotes[%d]", idx1) + } + } + } + { // Dynamic Field #11 'Validators' + binary.LittleEndian.PutUint32(dst[dstlen+524552:], uint32(len(dst)-dstlen)) + t := t.Validators + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Validators") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Validator) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Validators[%d]", idx1) + } + } + } + { // Dynamic Field #12 'Balances' + binary.LittleEndian.PutUint32(dst[dstlen+524556:], uint32(len(dst)-dstlen)) + t := t.Balances + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Balances") + } + dst = sszutils.MarshalUint64Slice(dst, t[:vlen]) + } + { // Dynamic Field #15 'PreviousEpochParticipation' + binary.LittleEndian.PutUint32(dst[dstlen+2687248:], uint32(len(dst)-dstlen)) + t := t.PreviousEpochParticipation + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "PreviousEpochParticipation") + } + dst = append(dst, t[:]...) + } + { // Dynamic Field #16 'CurrentEpochParticipation' + binary.LittleEndian.PutUint32(dst[dstlen+2687252:], uint32(len(dst)-dstlen)) + t := t.CurrentEpochParticipation + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "CurrentEpochParticipation") + } + dst = append(dst, t[:]...) + } + { // Dynamic Field #21 'InactivityScores' + binary.LittleEndian.PutUint32(dst[dstlen+2687377:], uint32(len(dst)-dstlen)) + t := t.InactivityScores + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "InactivityScores") + } + dst = sszutils.MarshalUint64Slice(dst, t[:vlen]) + } + { // Dynamic Field #27 'HistoricalSummaries' + binary.LittleEndian.PutUint32(dst[dstlen+2736677:], uint32(len(dst)-dstlen)) + t := t.HistoricalSummaries + vlen := len(t) + if vlen > 16777216 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalSummaries") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.HistoricalSummary) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "HistoricalSummaries[%d]", idx1) + } + } + } + { // Dynamic Field #34 'PendingDeposits' + binary.LittleEndian.PutUint32(dst[dstlen+2736729:], uint32(len(dst)-dstlen)) + t := t.PendingDeposits + vlen := len(t) + if vlen > 134217728 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingDeposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingDeposit) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "PendingDeposits[%d]", idx1) + } + } + } + { // Dynamic Field #35 'PendingPartialWithdrawals' + binary.LittleEndian.PutUint32(dst[dstlen+2736733:], uint32(len(dst)-dstlen)) + t := t.PendingPartialWithdrawals + vlen := len(t) + if vlen > 134217728 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingPartialWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingPartialWithdrawal) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "PendingPartialWithdrawals[%d]", idx1) + } + } + } + { // Dynamic Field #36 'PendingConsolidations' + binary.LittleEndian.PutUint32(dst[dstlen+2736737:], uint32(len(dst)-dstlen)) + t := t.PendingConsolidations + vlen := len(t) + if vlen > 262144 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 262144), "PendingConsolidations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingConsolidation) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "PendingConsolidations[%d]", idx1) + } + } + } + { // Dynamic Field #38 'Builders' + binary.LittleEndian.PutUint32(dst[dstlen+2737253:], uint32(len(dst)-dstlen)) + t := t.Builders + vlen := len(t) + if vlen > 1099511627776 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Builders") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(Builder) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Builders[%d]", idx1) + } + } + } + { // Dynamic Field #42 'BuilderPendingWithdrawals' + binary.LittleEndian.PutUint32(dst[dstlen+2741617:], uint32(len(dst)-dstlen)) + t := t.BuilderPendingWithdrawals + vlen := len(t) + if vlen > 134217728 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "BuilderPendingWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "BuilderPendingWithdrawals[%d]", idx1) + } + } + } + { // Dynamic Field #43 'LatestExecutionPayloadBid' + binary.LittleEndian.PutUint32(dst[dstlen+2741621:], uint32(len(dst)-dstlen)) + t := t.LatestExecutionPayloadBid + if t == nil { + t = new(ExecutionPayloadBid) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + } + { // Dynamic Field #44 'PayloadExpectedWithdrawals' + binary.LittleEndian.PutUint32(dst[dstlen+2741625:], uint32(len(dst)-dstlen)) + t := t.PayloadExpectedWithdrawals + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "PayloadExpectedWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Withdrawal) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "PayloadExpectedWithdrawals[%d]", idx1) + } + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *BeaconState to the given SSZ encoder using dynamic specifications. +func (t *BeaconState) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t [][]byte) (size int) + sizeFn10 func(ctx *encoderCtx, t []*generic.PendingPartialWithdrawal) (size int) + sizeFn11 func(ctx *encoderCtx, t []*generic.PendingConsolidation) (size int) + sizeFn12 func(ctx *encoderCtx, t []*Builder) (size int) + sizeFn13 func(ctx *encoderCtx, t []*BuilderPendingWithdrawal) (size int) + sizeFn14 func(ctx *encoderCtx, t *ExecutionPayloadBid) (size int) + sizeFn15 func(ctx *encoderCtx, t []*generic.Withdrawal) (size int) + sizeFn2 func(ctx *encoderCtx, t []*generic.Eth1Data) (size int) + sizeFn3 func(ctx *encoderCtx, t []*generic.Validator) (size int) + sizeFn4 func(ctx *encoderCtx, t []uint64) (size int) + sizeFn5 func(ctx *encoderCtx, t []byte) (size int) + sizeFn6 func(ctx *encoderCtx, t []byte) (size int) + sizeFn7 func(ctx *encoderCtx, t []uint64) (size int) + sizeFn8 func(ctx *encoderCtx, t []*generic.HistoricalSummary) (size int) + sizeFn9 func(ctx *encoderCtx, t []*generic.PendingDeposit) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for [][]byte + ctx.sizeFn1 = func(ctx *encoderCtx, t [][]byte) (size int) { + size += len(t) * 32 + return size + } + // size for []*generic.Eth1Data + ctx.sizeFn2 = func(ctx *encoderCtx, t []*generic.Eth1Data) (size int) { + size += len(t) * 72 + return size + } + // size for []*generic.Validator + ctx.sizeFn3 = func(ctx *encoderCtx, t []*generic.Validator) (size int) { + size += len(t) * 121 + return size + } + // size for []uint64 + ctx.sizeFn4 = func(ctx *encoderCtx, t []uint64) (size int) { + size += len(t) * 8 + return size + } + // size for []byte + ctx.sizeFn5 = func(ctx *encoderCtx, t []byte) (size int) { + size += len(t) + return size + } + // size for []byte + ctx.sizeFn6 = func(ctx *encoderCtx, t []byte) (size int) { + size += len(t) + return size + } + // size for []uint64 + ctx.sizeFn7 = func(ctx *encoderCtx, t []uint64) (size int) { + size += len(t) * 8 + return size + } + // size for []*generic.HistoricalSummary + ctx.sizeFn8 = func(ctx *encoderCtx, t []*generic.HistoricalSummary) (size int) { + size += len(t) * 64 + return size + } + // size for []*generic.PendingDeposit + ctx.sizeFn9 = func(ctx *encoderCtx, t []*generic.PendingDeposit) (size int) { + size += len(t) * 192 + return size + } + // size for []*generic.PendingPartialWithdrawal + ctx.sizeFn10 = func(ctx *encoderCtx, t []*generic.PendingPartialWithdrawal) (size int) { + size += len(t) * 24 + return size + } + // size for []*generic.PendingConsolidation + ctx.sizeFn11 = func(ctx *encoderCtx, t []*generic.PendingConsolidation) (size int) { + size += len(t) * 16 + return size + } + // size for []*Builder + ctx.sizeFn12 = func(ctx *encoderCtx, t []*Builder) (size int) { + size += len(t) * 93 + return size + } + // size for []*BuilderPendingWithdrawal + ctx.sizeFn13 = func(ctx *encoderCtx, t []*BuilderPendingWithdrawal) (size int) { + size += len(t) * 36 + return size + } + // size for *ExecutionPayloadBid + ctx.sizeFn14 = func(ctx *encoderCtx, t *ExecutionPayloadBid) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + // size for []*generic.Withdrawal + ctx.sizeFn15 = func(ctx *encoderCtx, t []*generic.Withdrawal) (size int) { + size += len(t) * 44 + return size + } + if t == nil { + t = new(BeaconState) + } + dstlen := enc.GetPosition() + dynoff := uint32(3134845) + { // Field #0 'GenesisTime' + enc.EncodeUint64(t.GenesisTime) + } + { // Field #1 'GenesisValidatorsRoot' + vlen := len(t.GenesisValidatorsRoot) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "GenesisValidatorsRoot") + } + enc.EncodeBytes(t.GenesisValidatorsRoot[:vlen]) + if vlen < 32 { + enc.EncodeZeroPadding((32 - vlen) * 1) + } + } + { // Field #2 'Slot' + enc.EncodeUint64(t.Slot) + } + { // Field #3 'Fork' + t := t.Fork + if t == nil { + t = new(generic.Fork) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "Fork") + } else { + enc.SetBuffer(buf) + } + } + { // Field #4 'LatestBlockHeader' + t := t.LatestBlockHeader + if t == nil { + t = new(generic.BeaconBlockHeader) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "LatestBlockHeader") + } else { + enc.SetBuffer(buf) + } + } + { // Field #5 'BlockRoots' + t := &t.BlockRoots + for idx1 := range 8192 { + enc.EncodeBytes(t[idx1][:32]) + } + } + { // Field #6 'StateRoots' + t := &t.StateRoots + for idx1 := range 8192 { + enc.EncodeBytes(t[idx1][:32]) + } + } + // Offset #7 'HistoricalRoots' + offset7 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.HistoricalRoots)) + } + { // Field #8 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } else { + enc.SetBuffer(buf) + } + } + // Offset #9 'Eth1DataVotes' + offset9 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn2(ctx, t.Eth1DataVotes)) + } + { // Field #10 'Eth1DepositIndex' + enc.EncodeUint64(t.Eth1DepositIndex) + } + // Offset #11 'Validators' + offset11 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn3(ctx, t.Validators)) + } + // Offset #12 'Balances' + offset12 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn4(ctx, t.Balances)) + } + { // Field #13 'RandaoMixes' + t := t.RandaoMixes + vlen := len(t) + if vlen > 65536 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 65536), "RandaoMixes") + } + for idx1 := range vlen { + vlen := len(t[idx1]) + if vlen > 32 { + return sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "RandaoMixes[%d]", idx1) + } + enc.EncodeBytes(t[idx1][:vlen]) + if vlen < 32 { + enc.EncodeZeroPadding((32 - vlen) * 1) + } + } + if vlen < 65536 { + enc.EncodeZeroPadding((65536 - vlen) * 32) + } + } + { // Field #14 'Slashings' + t := t.Slashings + vlen := len(t) + if vlen > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8192), "Slashings") + } + sszutils.EncodeUint64Slice(enc, t[:vlen]) + if vlen < 8192 { + enc.EncodeZeroPadding((8192 - vlen) * 8) + } + } + // Offset #15 'PreviousEpochParticipation' + offset15 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn5(ctx, t.PreviousEpochParticipation)) + } + // Offset #16 'CurrentEpochParticipation' + offset16 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn6(ctx, t.CurrentEpochParticipation)) + } + { // Field #17 'JustificationBits' + enc.EncodeBytes(t.JustificationBits[:1]) + } + { // Field #18 'PreviousJustifiedCheckpoint' + t := t.PreviousJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "PreviousJustifiedCheckpoint") + } else { + enc.SetBuffer(buf) + } + } + { // Field #19 'CurrentJustifiedCheckpoint' + t := t.CurrentJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "CurrentJustifiedCheckpoint") + } else { + enc.SetBuffer(buf) + } + } + { // Field #20 'FinalizedCheckpoint' + t := t.FinalizedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "FinalizedCheckpoint") + } else { + enc.SetBuffer(buf) + } + } + // Offset #21 'InactivityScores' + offset21 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn7(ctx, t.InactivityScores)) + } + { // Field #22 'CurrentSyncCommittee' + t := t.CurrentSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "CurrentSyncCommittee") + } else { + enc.SetBuffer(buf) + } + } + { // Field #23 'NextSyncCommittee' + t := t.NextSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "NextSyncCommittee") + } else { + enc.SetBuffer(buf) + } + } + { // Field #24 'LatestBlockHash' + enc.EncodeBytes(t.LatestBlockHash[:32]) + } + { // Field #25 'NextWithdrawalIndex' + enc.EncodeUint64(t.NextWithdrawalIndex) + } + { // Field #26 'NextWithdrawalValidatorIndex' + enc.EncodeUint64(t.NextWithdrawalValidatorIndex) + } + // Offset #27 'HistoricalSummaries' + offset27 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn8(ctx, t.HistoricalSummaries)) + } + { // Field #28 'DepositRequestsStartIndex' + enc.EncodeUint64(t.DepositRequestsStartIndex) + } + { // Field #29 'DepositBalanceToConsume' + enc.EncodeUint64(t.DepositBalanceToConsume) + } + { // Field #30 'ExitBalanceToConsume' + enc.EncodeUint64(t.ExitBalanceToConsume) + } + { // Field #31 'EarliestExitEpoch' + enc.EncodeUint64(t.EarliestExitEpoch) + } + { // Field #32 'ConsolidationBalanceToConsume' + enc.EncodeUint64(t.ConsolidationBalanceToConsume) + } + { // Field #33 'EarliestConsolidationEpoch' + enc.EncodeUint64(t.EarliestConsolidationEpoch) + } + // Offset #34 'PendingDeposits' + offset34 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn9(ctx, t.PendingDeposits)) + } + // Offset #35 'PendingPartialWithdrawals' + offset35 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn10(ctx, t.PendingPartialWithdrawals)) + } + // Offset #36 'PendingConsolidations' + offset36 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn11(ctx, t.PendingConsolidations)) + } + { // Field #37 'ProposerLookahead' + t := t.ProposerLookahead + vlen := len(t) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "ProposerLookahead") + } + sszutils.EncodeUint64Slice(enc, t[:vlen]) + if vlen < 64 { + enc.EncodeZeroPadding((64 - vlen) * 8) + } + } + // Offset #38 'Builders' + offset38 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn12(ctx, t.Builders)) + } + { // Field #39 'NextWithdrawalBuilderIndex' + enc.EncodeUint64(t.NextWithdrawalBuilderIndex) + } + { // Field #40 'ExecutionPayloadAvailability' + vlen := len(t.ExecutionPayloadAvailability) + if vlen > 1024 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 1024), "ExecutionPayloadAvailability") + } + enc.EncodeBytes(t.ExecutionPayloadAvailability[:vlen]) + if vlen < 1024 { + enc.EncodeZeroPadding((1024 - vlen) * 1) + } + } + { // Field #41 'BuilderPendingPayments' + t := &t.BuilderPendingPayments + for idx1 := range 64 { + t := t[idx1] + if t == nil { + t = new(BuilderPendingPayment) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingPayments[%d]", idx1) + } + } + } + // Offset #42 'BuilderPendingWithdrawals' + offset42 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn13(ctx, t.BuilderPendingWithdrawals)) + } + // Offset #43 'LatestExecutionPayloadBid' + offset43 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn14(ctx, t.LatestExecutionPayloadBid)) + } + // Offset #44 'PayloadExpectedWithdrawals' + offset44 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn15(ctx, t.PayloadExpectedWithdrawals)) + } + { // Field #45 'PtcWindow' + t := &t.PtcWindow + for idx1 := range 96 { + t := &t[idx1] + sszutils.EncodeUint64Slice(enc, t[:512]) + } + } + { // Dynamic Field #7 'HistoricalRoots' + if canSeek { + enc.EncodeOffsetAt(offset7, uint32(enc.GetPosition()-dstlen)) + } + t := t.HistoricalRoots + vlen := len(t) + if vlen > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalRoots") + } + for idx1 := range vlen { + vlen := len(t[idx1]) + if vlen > 32 { + return sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "HistoricalRoots[%d]", idx1) + } + enc.EncodeBytes(t[idx1][:vlen]) + if vlen < 32 { + enc.EncodeZeroPadding((32 - vlen) * 1) + } + } + } + { // Dynamic Field #9 'Eth1DataVotes' + if canSeek { + enc.EncodeOffsetAt(offset9, uint32(enc.GetPosition()-dstlen)) + } + t := t.Eth1DataVotes + vlen := len(t) + if vlen > 2048 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2048), "Eth1DataVotes") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Eth1Data) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "Eth1DataVotes[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #11 'Validators' + if canSeek { + enc.EncodeOffsetAt(offset11, uint32(enc.GetPosition()-dstlen)) + } + t := t.Validators + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Validators") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Validator) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "Validators[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #12 'Balances' + if canSeek { + enc.EncodeOffsetAt(offset12, uint32(enc.GetPosition()-dstlen)) + } + t := t.Balances + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Balances") + } + sszutils.EncodeUint64Slice(enc, t[:vlen]) + } + { // Dynamic Field #15 'PreviousEpochParticipation' + if canSeek { + enc.EncodeOffsetAt(offset15, uint32(enc.GetPosition()-dstlen)) + } + t := t.PreviousEpochParticipation + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "PreviousEpochParticipation") + } + enc.EncodeBytes(t[:]) + } + { // Dynamic Field #16 'CurrentEpochParticipation' + if canSeek { + enc.EncodeOffsetAt(offset16, uint32(enc.GetPosition()-dstlen)) + } + t := t.CurrentEpochParticipation + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "CurrentEpochParticipation") + } + enc.EncodeBytes(t[:]) + } + { // Dynamic Field #21 'InactivityScores' + if canSeek { + enc.EncodeOffsetAt(offset21, uint32(enc.GetPosition()-dstlen)) + } + t := t.InactivityScores + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "InactivityScores") + } + sszutils.EncodeUint64Slice(enc, t[:vlen]) + } + { // Dynamic Field #27 'HistoricalSummaries' + if canSeek { + enc.EncodeOffsetAt(offset27, uint32(enc.GetPosition()-dstlen)) + } + t := t.HistoricalSummaries + vlen := len(t) + if vlen > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalSummaries") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.HistoricalSummary) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "HistoricalSummaries[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #34 'PendingDeposits' + if canSeek { + enc.EncodeOffsetAt(offset34, uint32(enc.GetPosition()-dstlen)) + } + t := t.PendingDeposits + vlen := len(t) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingDeposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingDeposit) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "PendingDeposits[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #35 'PendingPartialWithdrawals' + if canSeek { + enc.EncodeOffsetAt(offset35, uint32(enc.GetPosition()-dstlen)) + } + t := t.PendingPartialWithdrawals + vlen := len(t) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingPartialWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingPartialWithdrawal) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "PendingPartialWithdrawals[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #36 'PendingConsolidations' + if canSeek { + enc.EncodeOffsetAt(offset36, uint32(enc.GetPosition()-dstlen)) + } + t := t.PendingConsolidations + vlen := len(t) + if vlen > 262144 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 262144), "PendingConsolidations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.PendingConsolidation) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "PendingConsolidations[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + { // Dynamic Field #38 'Builders' + if canSeek { + enc.EncodeOffsetAt(offset38, uint32(enc.GetPosition()-dstlen)) + } + t := t.Builders + vlen := len(t) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Builders") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(Builder) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Builders[%d]", idx1) + } + } + } + { // Dynamic Field #42 'BuilderPendingWithdrawals' + if canSeek { + enc.EncodeOffsetAt(offset42, uint32(enc.GetPosition()-dstlen)) + } + t := t.BuilderPendingWithdrawals + vlen := len(t) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "BuilderPendingWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingWithdrawals[%d]", idx1) + } + } + } + { // Dynamic Field #43 'LatestExecutionPayloadBid' + if canSeek { + enc.EncodeOffsetAt(offset43, uint32(enc.GetPosition()-dstlen)) + } + t := t.LatestExecutionPayloadBid + if t == nil { + t = new(ExecutionPayloadBid) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + } + { // Dynamic Field #44 'PayloadExpectedWithdrawals' + if canSeek { + enc.EncodeOffsetAt(offset44, uint32(enc.GetPosition()-dstlen)) + } + t := t.PayloadExpectedWithdrawals + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "PayloadExpectedWithdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Withdrawal) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadExpectedWithdrawals[%d]", idx1) + } else { + enc.SetBuffer(buf) + } + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BeaconState from SSZ-encoded bytes using dynamic specifications. +func (t *BeaconState) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 3134845 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 3134845) + } + { // Field #0 'GenesisTime' (static) + buf := buf[0:8] + t.GenesisTime = binary.LittleEndian.Uint64(buf) + } + { // Field #1 'GenesisValidatorsRoot' (static) + buf := buf[8:40] + t.GenesisValidatorsRoot = sszutils.ExpandSlice(t.GenesisValidatorsRoot, 32) + copy(t.GenesisValidatorsRoot[:], buf) + } + { // Field #2 'Slot' (static) + buf := buf[40:48] + t.Slot = binary.LittleEndian.Uint64(buf) + } + { // Field #3 'Fork' (static) + buf := buf[48:64] + if t.Fork == nil { + t.Fork = new(generic.Fork) + } + if err = t.Fork.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "Fork") + } + } + { // Field #4 'LatestBlockHeader' (static) + buf := buf[64:176] + if t.LatestBlockHeader == nil { + t.LatestBlockHeader = new(generic.BeaconBlockHeader) + } + if err = t.LatestBlockHeader.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "LatestBlockHeader") + } + } + { // Field #5 'BlockRoots' (static) + buf := buf[176:262320] + val1 := t.BlockRoots + sszutils.UnmarshalFixedBytesSlice(val1[:8192], buf) + t.BlockRoots = val1 + } + { // Field #6 'StateRoots' (static) + buf := buf[262320:524464] + val2 := t.StateRoots + sszutils.UnmarshalFixedBytesSlice(val2[:8192], buf) + t.StateRoots = val2 + } + // Field #7 'HistoricalRoots' (offset) + offset7 := int(binary.LittleEndian.Uint32(buf[524464:524468])) + if offset7 != 3134845 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset7, 3134845), "HistoricalRoots:o") + } + { // Field #8 'Eth1Data' (static) + buf := buf[524468:524540] + if t.Eth1Data == nil { + t.Eth1Data = new(generic.Eth1Data) + } + if err = t.Eth1Data.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + } + // Field #9 'Eth1DataVotes' (offset) + offset9 := int(binary.LittleEndian.Uint32(buf[524540:524544])) + if offset9 < offset7 || offset9 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset9, offset7, buflen), "Eth1DataVotes:o") + } + { // Field #10 'Eth1DepositIndex' (static) + buf := buf[524544:524552] + t.Eth1DepositIndex = binary.LittleEndian.Uint64(buf) + } + // Field #11 'Validators' (offset) + offset11 := int(binary.LittleEndian.Uint32(buf[524552:524556])) + if offset11 < offset9 || offset11 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset11, offset9, buflen), "Validators:o") + } + // Field #12 'Balances' (offset) + offset12 := int(binary.LittleEndian.Uint32(buf[524556:524560])) + if offset12 < offset11 || offset12 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset12, offset11, buflen), "Balances:o") + } + { // Field #13 'RandaoMixes' (static) + buf := buf[524560:2621712] + val3 := t.RandaoMixes + val3 = sszutils.ExpandSlice(val3, 65536) + for idx1 := range 65536 { + buf := buf[32*idx1 : 32*(idx1+1)] + val3[idx1] = sszutils.ExpandSlice(val3[idx1], 32) + copy(val3[idx1][:], buf) + } + t.RandaoMixes = val3 + } + { // Field #14 'Slashings' (static) + buf := buf[2621712:2687248] + val4 := t.Slashings + val4 = sszutils.ExpandSlice(val4, 8192) + sszutils.UnmarshalUint64Slice(val4[:8192], buf) + t.Slashings = val4 + } + // Field #15 'PreviousEpochParticipation' (offset) + offset15 := int(binary.LittleEndian.Uint32(buf[2687248:2687252])) + if offset15 < offset12 || offset15 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset15, offset12, buflen), "PreviousEpochParticipation:o") + } + // Field #16 'CurrentEpochParticipation' (offset) + offset16 := int(binary.LittleEndian.Uint32(buf[2687252:2687256])) + if offset16 < offset15 || offset16 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset16, offset15, buflen), "CurrentEpochParticipation:o") + } + { // Field #17 'JustificationBits' (static) + buf := buf[2687256:2687257] + copy(t.JustificationBits[:], buf) + } + { // Field #18 'PreviousJustifiedCheckpoint' (static) + buf := buf[2687257:2687297] + if t.PreviousJustifiedCheckpoint == nil { + t.PreviousJustifiedCheckpoint = new(generic.Checkpoint) + } + if err = t.PreviousJustifiedCheckpoint.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "PreviousJustifiedCheckpoint") + } + } + { // Field #19 'CurrentJustifiedCheckpoint' (static) + buf := buf[2687297:2687337] + if t.CurrentJustifiedCheckpoint == nil { + t.CurrentJustifiedCheckpoint = new(generic.Checkpoint) + } + if err = t.CurrentJustifiedCheckpoint.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "CurrentJustifiedCheckpoint") + } + } + { // Field #20 'FinalizedCheckpoint' (static) + buf := buf[2687337:2687377] + if t.FinalizedCheckpoint == nil { + t.FinalizedCheckpoint = new(generic.Checkpoint) + } + if err = t.FinalizedCheckpoint.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "FinalizedCheckpoint") + } + } + // Field #21 'InactivityScores' (offset) + offset21 := int(binary.LittleEndian.Uint32(buf[2687377:2687381])) + if offset21 < offset16 || offset21 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset21, offset16, buflen), "InactivityScores:o") + } + { // Field #22 'CurrentSyncCommittee' (static) + buf := buf[2687381:2712005] + if t.CurrentSyncCommittee == nil { + t.CurrentSyncCommittee = new(generic.SyncCommittee) + } + if err = t.CurrentSyncCommittee.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "CurrentSyncCommittee") + } + } + { // Field #23 'NextSyncCommittee' (static) + buf := buf[2712005:2736629] + if t.NextSyncCommittee == nil { + t.NextSyncCommittee = new(generic.SyncCommittee) + } + if err = t.NextSyncCommittee.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "NextSyncCommittee") + } + } + { // Field #24 'LatestBlockHash' (static) + buf := buf[2736629:2736661] + copy(t.LatestBlockHash[:], buf) + } + { // Field #25 'NextWithdrawalIndex' (static) + buf := buf[2736661:2736669] + t.NextWithdrawalIndex = binary.LittleEndian.Uint64(buf) + } + { // Field #26 'NextWithdrawalValidatorIndex' (static) + buf := buf[2736669:2736677] + t.NextWithdrawalValidatorIndex = binary.LittleEndian.Uint64(buf) + } + // Field #27 'HistoricalSummaries' (offset) + offset27 := int(binary.LittleEndian.Uint32(buf[2736677:2736681])) + if offset27 < offset21 || offset27 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset27, offset21, buflen), "HistoricalSummaries:o") + } + { // Field #28 'DepositRequestsStartIndex' (static) + buf := buf[2736681:2736689] + t.DepositRequestsStartIndex = binary.LittleEndian.Uint64(buf) + } + { // Field #29 'DepositBalanceToConsume' (static) + buf := buf[2736689:2736697] + t.DepositBalanceToConsume = binary.LittleEndian.Uint64(buf) + } + { // Field #30 'ExitBalanceToConsume' (static) + buf := buf[2736697:2736705] + t.ExitBalanceToConsume = binary.LittleEndian.Uint64(buf) + } + { // Field #31 'EarliestExitEpoch' (static) + buf := buf[2736705:2736713] + t.EarliestExitEpoch = binary.LittleEndian.Uint64(buf) + } + { // Field #32 'ConsolidationBalanceToConsume' (static) + buf := buf[2736713:2736721] + t.ConsolidationBalanceToConsume = binary.LittleEndian.Uint64(buf) + } + { // Field #33 'EarliestConsolidationEpoch' (static) + buf := buf[2736721:2736729] + t.EarliestConsolidationEpoch = binary.LittleEndian.Uint64(buf) + } + // Field #34 'PendingDeposits' (offset) + offset34 := int(binary.LittleEndian.Uint32(buf[2736729:2736733])) + if offset34 < offset27 || offset34 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset34, offset27, buflen), "PendingDeposits:o") + } + // Field #35 'PendingPartialWithdrawals' (offset) + offset35 := int(binary.LittleEndian.Uint32(buf[2736733:2736737])) + if offset35 < offset34 || offset35 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset35, offset34, buflen), "PendingPartialWithdrawals:o") + } + // Field #36 'PendingConsolidations' (offset) + offset36 := int(binary.LittleEndian.Uint32(buf[2736737:2736741])) + if offset36 < offset35 || offset36 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset36, offset35, buflen), "PendingConsolidations:o") + } + { // Field #37 'ProposerLookahead' (static) + buf := buf[2736741:2737253] + val5 := t.ProposerLookahead + val5 = sszutils.ExpandSlice(val5, 64) + sszutils.UnmarshalUint64Slice(val5[:64], buf) + t.ProposerLookahead = val5 + } + // Field #38 'Builders' (offset) + offset38 := int(binary.LittleEndian.Uint32(buf[2737253:2737257])) + if offset38 < offset36 || offset38 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset38, offset36, buflen), "Builders:o") + } + { // Field #39 'NextWithdrawalBuilderIndex' (static) + buf := buf[2737257:2737265] + t.NextWithdrawalBuilderIndex = binary.LittleEndian.Uint64(buf) + } + { // Field #40 'ExecutionPayloadAvailability' (static) + buf := buf[2737265:2738289] + t.ExecutionPayloadAvailability = sszutils.ExpandSlice(t.ExecutionPayloadAvailability, 1024) + copy(t.ExecutionPayloadAvailability[:], buf) + } + { // Field #41 'BuilderPendingPayments' (static) + buf := buf[2738289:2741617] + val6 := t.BuilderPendingPayments + for idx1 := range 64 { + if val6[idx1] == nil { + val6[idx1] = new(BuilderPendingPayment) + } + buf := buf[52*idx1 : 52*(idx1+1)] + if err = val6[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingPayments[%d]", idx1) + } + } + t.BuilderPendingPayments = val6 + } + // Field #42 'BuilderPendingWithdrawals' (offset) + offset42 := int(binary.LittleEndian.Uint32(buf[2741617:2741621])) + if offset42 < offset38 || offset42 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset42, offset38, buflen), "BuilderPendingWithdrawals:o") + } + // Field #43 'LatestExecutionPayloadBid' (offset) + offset43 := int(binary.LittleEndian.Uint32(buf[2741621:2741625])) + if offset43 < offset42 || offset43 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset43, offset42, buflen), "LatestExecutionPayloadBid:o") + } + // Field #44 'PayloadExpectedWithdrawals' (offset) + offset44 := int(binary.LittleEndian.Uint32(buf[2741625:2741629])) + if offset44 < offset43 || offset44 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset44, offset43, buflen), "PayloadExpectedWithdrawals:o") + } + { // Field #45 'PtcWindow' (static) + buf := buf[2741629:3134845] + val7 := t.PtcWindow + for idx1 := range 96 { + val8 := val7[idx1] + buf := buf[4096*idx1 : 4096*(idx1+1)] + sszutils.UnmarshalUint64Slice(val8[:512], buf) + val7[idx1] = val8 + } + t.PtcWindow = val7 + } + { // Field #7 'HistoricalRoots' (dynamic) + buf := buf[offset7:offset9] + val9 := t.HistoricalRoots + itemCount := len(buf) / 32 + if len(buf)%32 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 32), "HistoricalRoots") + } + if itemCount > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16777216), "HistoricalRoots") + } + val9 = sszutils.ExpandSlice(val9, itemCount) + for idx1 := range itemCount { + buf := buf[32*idx1 : 32*(idx1+1)] + val9[idx1] = sszutils.ExpandSlice(val9[idx1], 32) + copy(val9[idx1][:], buf) + } + t.HistoricalRoots = val9 + } + { // Field #9 'Eth1DataVotes' (dynamic) + buf := buf[offset9:offset11] + val10 := t.Eth1DataVotes + itemCount := len(buf) / 72 + if len(buf)%72 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 72), "Eth1DataVotes") + } + if itemCount > 2048 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 2048), "Eth1DataVotes") + } + val10 = sszutils.ExpandSlice(val10, itemCount) + for idx1 := range itemCount { + if val10[idx1] == nil { + val10[idx1] = new(generic.Eth1Data) + } + buf := buf[72*idx1 : 72*(idx1+1)] + if err = val10[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "Eth1DataVotes[%d]", idx1) + } + } + t.Eth1DataVotes = val10 + } + { // Field #11 'Validators' (dynamic) + buf := buf[offset11:offset12] + val11 := t.Validators + itemCount := len(buf) / 121 + if len(buf)%121 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 121), "Validators") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Validators") + } + val11 = sszutils.ExpandSlice(val11, itemCount) + for idx1 := range itemCount { + if val11[idx1] == nil { + val11[idx1] = new(generic.Validator) + } + buf := buf[121*idx1 : 121*(idx1+1)] + if err = val11[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "Validators[%d]", idx1) + } + } + t.Validators = val11 + } + { // Field #12 'Balances' (dynamic) + buf := buf[offset12:offset15] + val12 := t.Balances + itemCount := len(buf) / 8 + if len(buf)%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 8), "Balances") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Balances") + } + val12 = sszutils.ExpandSlice(val12, itemCount) + sszutils.UnmarshalUint64Slice(val12, buf) + t.Balances = val12 + } + { // Field #15 'PreviousEpochParticipation' (dynamic) + buf := buf[offset15:offset16] + val13 := t.PreviousEpochParticipation + if len(buf) > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(len(buf), 1099511627776), "PreviousEpochParticipation") + } + val13 = sszutils.ExpandSlice(val13, len(buf)) + copy(val13[:], buf) + t.PreviousEpochParticipation = val13 + } + { // Field #16 'CurrentEpochParticipation' (dynamic) + buf := buf[offset16:offset21] + val14 := t.CurrentEpochParticipation + if len(buf) > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(len(buf), 1099511627776), "CurrentEpochParticipation") + } + val14 = sszutils.ExpandSlice(val14, len(buf)) + copy(val14[:], buf) + t.CurrentEpochParticipation = val14 + } + { // Field #21 'InactivityScores' (dynamic) + buf := buf[offset21:offset27] + val15 := t.InactivityScores + itemCount := len(buf) / 8 + if len(buf)%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 8), "InactivityScores") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "InactivityScores") + } + val15 = sszutils.ExpandSlice(val15, itemCount) + sszutils.UnmarshalUint64Slice(val15, buf) + t.InactivityScores = val15 + } + { // Field #27 'HistoricalSummaries' (dynamic) + buf := buf[offset27:offset34] + val16 := t.HistoricalSummaries + itemCount := len(buf) / 64 + if len(buf)%64 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 64), "HistoricalSummaries") + } + if itemCount > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16777216), "HistoricalSummaries") + } + val16 = sszutils.ExpandSlice(val16, itemCount) + for idx1 := range itemCount { + if val16[idx1] == nil { + val16[idx1] = new(generic.HistoricalSummary) + } + buf := buf[64*idx1 : 64*(idx1+1)] + if err = val16[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "HistoricalSummaries[%d]", idx1) + } + } + t.HistoricalSummaries = val16 + } + { // Field #34 'PendingDeposits' (dynamic) + buf := buf[offset34:offset35] + val17 := t.PendingDeposits + itemCount := len(buf) / 192 + if len(buf)%192 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 192), "PendingDeposits") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "PendingDeposits") + } + val17 = sszutils.ExpandSlice(val17, itemCount) + for idx1 := range itemCount { + if val17[idx1] == nil { + val17[idx1] = new(generic.PendingDeposit) + } + buf := buf[192*idx1 : 192*(idx1+1)] + if err = val17[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "PendingDeposits[%d]", idx1) + } + } + t.PendingDeposits = val17 + } + { // Field #35 'PendingPartialWithdrawals' (dynamic) + buf := buf[offset35:offset36] + val18 := t.PendingPartialWithdrawals + itemCount := len(buf) / 24 + if len(buf)%24 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 24), "PendingPartialWithdrawals") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "PendingPartialWithdrawals") + } + val18 = sszutils.ExpandSlice(val18, itemCount) + for idx1 := range itemCount { + if val18[idx1] == nil { + val18[idx1] = new(generic.PendingPartialWithdrawal) + } + buf := buf[24*idx1 : 24*(idx1+1)] + if err = val18[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "PendingPartialWithdrawals[%d]", idx1) + } + } + t.PendingPartialWithdrawals = val18 + } + { // Field #36 'PendingConsolidations' (dynamic) + buf := buf[offset36:offset38] + val19 := t.PendingConsolidations + itemCount := len(buf) / 16 + if len(buf)%16 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 16), "PendingConsolidations") + } + if itemCount > 262144 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 262144), "PendingConsolidations") + } + val19 = sszutils.ExpandSlice(val19, itemCount) + for idx1 := range itemCount { + if val19[idx1] == nil { + val19[idx1] = new(generic.PendingConsolidation) + } + buf := buf[16*idx1 : 16*(idx1+1)] + if err = val19[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "PendingConsolidations[%d]", idx1) + } + } + t.PendingConsolidations = val19 + } + { // Field #38 'Builders' (dynamic) + buf := buf[offset38:offset42] + val20 := t.Builders + itemCount := len(buf) / 93 + if len(buf)%93 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 93), "Builders") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Builders") + } + val20 = sszutils.ExpandSlice(val20, itemCount) + for idx1 := range itemCount { + if val20[idx1] == nil { + val20[idx1] = new(Builder) + } + buf := buf[93*idx1 : 93*(idx1+1)] + if err = val20[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Builders[%d]", idx1) + } + } + t.Builders = val20 + } + { // Field #42 'BuilderPendingWithdrawals' (dynamic) + buf := buf[offset42:offset43] + val21 := t.BuilderPendingWithdrawals + itemCount := len(buf) / 36 + if len(buf)%36 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 36), "BuilderPendingWithdrawals") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "BuilderPendingWithdrawals") + } + val21 = sszutils.ExpandSlice(val21, itemCount) + for idx1 := range itemCount { + if val21[idx1] == nil { + val21[idx1] = new(BuilderPendingWithdrawal) + } + buf := buf[36*idx1 : 36*(idx1+1)] + if err = val21[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingWithdrawals[%d]", idx1) + } + } + t.BuilderPendingWithdrawals = val21 + } + { // Field #43 'LatestExecutionPayloadBid' (dynamic) + buf := buf[offset43:offset44] + if t.LatestExecutionPayloadBid == nil { + t.LatestExecutionPayloadBid = new(ExecutionPayloadBid) + } + if err = t.LatestExecutionPayloadBid.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + } + { // Field #44 'PayloadExpectedWithdrawals' (dynamic) + buf := buf[offset44:] + val22 := t.PayloadExpectedWithdrawals + itemCount := len(buf) / 44 + if len(buf)%44 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 44), "PayloadExpectedWithdrawals") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "PayloadExpectedWithdrawals") + } + val22 = sszutils.ExpandSlice(val22, itemCount) + for idx1 := range itemCount { + if val22[idx1] == nil { + val22[idx1] = new(generic.Withdrawal) + } + buf := buf[44*idx1 : 44*(idx1+1)] + if err = val22[idx1].UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadExpectedWithdrawals[%d]", idx1) + } + } + t.PayloadExpectedWithdrawals = val22 + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *BeaconState from the given SSZ decoder using dynamic specifications. +func (t *BeaconState) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(3134845) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(3134845)) + } + // Field #0 'GenesisTime' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "GenesisTime") + } else { + t.GenesisTime = val + } + // Field #1 'GenesisValidatorsRoot' (static) + t.GenesisValidatorsRoot = sszutils.ExpandSlice(t.GenesisValidatorsRoot, 32) + if _, err = dec.DecodeBytes(t.GenesisValidatorsRoot[:32]); err != nil { + return err + } + // Field #2 'Slot' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Slot") + } else { + t.Slot = val + } + // Field #3 'Fork' (static) + if t.Fork == nil { + t.Fork = new(generic.Fork) + } + if err = t.Fork.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Fork") + } + // Field #4 'LatestBlockHeader' (static) + if t.LatestBlockHeader == nil { + t.LatestBlockHeader = new(generic.BeaconBlockHeader) + } + if err = t.LatestBlockHeader.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "LatestBlockHeader") + } + { // Field #5 'BlockRoots' (static) + val1 := t.BlockRoots + startPos1 := dec.GetPosition() + for idx1 := range 8192 { + if _, err = dec.DecodeBytes(val1[idx1][:32]); err != nil { + return err + } + if dec.GetPosition() != startPos1+int(32*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos1+int(32*(idx1+1))), "BlockRoots[%d]", idx1) + } + } + t.BlockRoots = val1 + } + { // Field #6 'StateRoots' (static) + val2 := t.StateRoots + startPos2 := dec.GetPosition() + for idx1 := range 8192 { + if _, err = dec.DecodeBytes(val2[idx1][:32]); err != nil { + return err + } + if dec.GetPosition() != startPos2+int(32*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos2+int(32*(idx1+1))), "StateRoots[%d]", idx1) + } + } + t.StateRoots = val2 + } + // Field #7 'HistoricalRoots' (offset) + offset7, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "HistoricalRoots") + } + if offset7 != uint32(3134845) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset7, 3134845), "HistoricalRoots") + } + // Field #8 'Eth1Data' (static) + if t.Eth1Data == nil { + t.Eth1Data = new(generic.Eth1Data) + } + if err = t.Eth1Data.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + // Field #9 'Eth1DataVotes' (offset) + offset9, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Eth1DataVotes") + } + if offset9 < offset7 || offset9 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset9, offset7, maxOffset), "Eth1DataVotes") + } + // Field #10 'Eth1DepositIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Eth1DepositIndex") + } else { + t.Eth1DepositIndex = val + } + // Field #11 'Validators' (offset) + offset11, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Validators") + } + if offset11 < offset9 || offset11 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset11, offset9, maxOffset), "Validators") + } + // Field #12 'Balances' (offset) + offset12, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Balances") + } + if offset12 < offset11 || offset12 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset12, offset11, maxOffset), "Balances") + } + { // Field #13 'RandaoMixes' (static) + val3 := t.RandaoMixes + val3 = sszutils.ExpandSlice(val3, 65536) + startPos3 := dec.GetPosition() + for idx1 := range 65536 { + val3[idx1] = sszutils.ExpandSlice(val3[idx1], 32) + if _, err = dec.DecodeBytes(val3[idx1][:32]); err != nil { + return err + } + if dec.GetPosition() != startPos3+int(32*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos3+int(32*(idx1+1))), "RandaoMixes[%d]", idx1) + } + } + t.RandaoMixes = val3 + } + { // Field #14 'Slashings' (static) + val4 := t.Slashings + val4 = sszutils.ExpandSlice(val4, 8192) + if err = sszutils.DecodeUint64Slice(dec, val4[:8192]); err != nil { + return sszutils.ErrorWithPath(err, "Slashings") + } + t.Slashings = val4 + } + // Field #15 'PreviousEpochParticipation' (offset) + offset15, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PreviousEpochParticipation") + } + if offset15 < offset12 || offset15 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset15, offset12, maxOffset), "PreviousEpochParticipation") + } + // Field #16 'CurrentEpochParticipation' (offset) + offset16, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "CurrentEpochParticipation") + } + if offset16 < offset15 || offset16 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset16, offset15, maxOffset), "CurrentEpochParticipation") + } + // Field #17 'JustificationBits' (static) + if _, err = dec.DecodeBytes(t.JustificationBits[:1]); err != nil { + return err + } + // Field #18 'PreviousJustifiedCheckpoint' (static) + if t.PreviousJustifiedCheckpoint == nil { + t.PreviousJustifiedCheckpoint = new(generic.Checkpoint) + } + if err = t.PreviousJustifiedCheckpoint.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "PreviousJustifiedCheckpoint") + } + // Field #19 'CurrentJustifiedCheckpoint' (static) + if t.CurrentJustifiedCheckpoint == nil { + t.CurrentJustifiedCheckpoint = new(generic.Checkpoint) + } + if err = t.CurrentJustifiedCheckpoint.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "CurrentJustifiedCheckpoint") + } + // Field #20 'FinalizedCheckpoint' (static) + if t.FinalizedCheckpoint == nil { + t.FinalizedCheckpoint = new(generic.Checkpoint) + } + if err = t.FinalizedCheckpoint.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "FinalizedCheckpoint") + } + // Field #21 'InactivityScores' (offset) + offset21, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "InactivityScores") + } + if offset21 < offset16 || offset21 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset21, offset16, maxOffset), "InactivityScores") + } + // Field #22 'CurrentSyncCommittee' (static) + if t.CurrentSyncCommittee == nil { + t.CurrentSyncCommittee = new(generic.SyncCommittee) + } + if err = t.CurrentSyncCommittee.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "CurrentSyncCommittee") + } + // Field #23 'NextSyncCommittee' (static) + if t.NextSyncCommittee == nil { + t.NextSyncCommittee = new(generic.SyncCommittee) + } + if err = t.NextSyncCommittee.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "NextSyncCommittee") + } + // Field #24 'LatestBlockHash' (static) + if _, err = dec.DecodeBytes(t.LatestBlockHash[:32]); err != nil { + return err + } + // Field #25 'NextWithdrawalIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "NextWithdrawalIndex") + } else { + t.NextWithdrawalIndex = val + } + // Field #26 'NextWithdrawalValidatorIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "NextWithdrawalValidatorIndex") + } else { + t.NextWithdrawalValidatorIndex = val + } + // Field #27 'HistoricalSummaries' (offset) + offset27, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "HistoricalSummaries") + } + if offset27 < offset21 || offset27 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset27, offset21, maxOffset), "HistoricalSummaries") + } + // Field #28 'DepositRequestsStartIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "DepositRequestsStartIndex") + } else { + t.DepositRequestsStartIndex = val + } + // Field #29 'DepositBalanceToConsume' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "DepositBalanceToConsume") + } else { + t.DepositBalanceToConsume = val + } + // Field #30 'ExitBalanceToConsume' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "ExitBalanceToConsume") + } else { + t.ExitBalanceToConsume = val + } + // Field #31 'EarliestExitEpoch' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "EarliestExitEpoch") + } else { + t.EarliestExitEpoch = val + } + // Field #32 'ConsolidationBalanceToConsume' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "ConsolidationBalanceToConsume") + } else { + t.ConsolidationBalanceToConsume = val + } + // Field #33 'EarliestConsolidationEpoch' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "EarliestConsolidationEpoch") + } else { + t.EarliestConsolidationEpoch = val + } + // Field #34 'PendingDeposits' (offset) + offset34, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PendingDeposits") + } + if offset34 < offset27 || offset34 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset34, offset27, maxOffset), "PendingDeposits") + } + // Field #35 'PendingPartialWithdrawals' (offset) + offset35, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PendingPartialWithdrawals") + } + if offset35 < offset34 || offset35 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset35, offset34, maxOffset), "PendingPartialWithdrawals") + } + // Field #36 'PendingConsolidations' (offset) + offset36, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PendingConsolidations") + } + if offset36 < offset35 || offset36 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset36, offset35, maxOffset), "PendingConsolidations") + } + { // Field #37 'ProposerLookahead' (static) + val5 := t.ProposerLookahead + val5 = sszutils.ExpandSlice(val5, 64) + if err = sszutils.DecodeUint64Slice(dec, val5[:64]); err != nil { + return sszutils.ErrorWithPath(err, "ProposerLookahead") + } + t.ProposerLookahead = val5 + } + // Field #38 'Builders' (offset) + offset38, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Builders") + } + if offset38 < offset36 || offset38 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset38, offset36, maxOffset), "Builders") + } + // Field #39 'NextWithdrawalBuilderIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "NextWithdrawalBuilderIndex") + } else { + t.NextWithdrawalBuilderIndex = val + } + // Field #40 'ExecutionPayloadAvailability' (static) + t.ExecutionPayloadAvailability = sszutils.ExpandSlice(t.ExecutionPayloadAvailability, 1024) + if _, err = dec.DecodeBytes(t.ExecutionPayloadAvailability[:1024]); err != nil { + return err + } + { // Field #41 'BuilderPendingPayments' (static) + val6 := t.BuilderPendingPayments + startPos4 := dec.GetPosition() + for idx1 := range 64 { + if val6[idx1] == nil { + val6[idx1] = new(BuilderPendingPayment) + } + if err = val6[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingPayments[%d]", idx1) + } + if dec.GetPosition() != startPos4+int(52*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos4+int(52*(idx1+1))), "BuilderPendingPayments[%d]", idx1) + } + } + t.BuilderPendingPayments = val6 + } + // Field #42 'BuilderPendingWithdrawals' (offset) + offset42, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "BuilderPendingWithdrawals") + } + if offset42 < offset38 || offset42 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset42, offset38, maxOffset), "BuilderPendingWithdrawals") + } + // Field #43 'LatestExecutionPayloadBid' (offset) + offset43, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + if offset43 < offset42 || offset43 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset43, offset42, maxOffset), "LatestExecutionPayloadBid") + } + // Field #44 'PayloadExpectedWithdrawals' (offset) + offset44, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PayloadExpectedWithdrawals") + } + if offset44 < offset43 || offset44 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset44, offset43, maxOffset), "PayloadExpectedWithdrawals") + } + { // Field #45 'PtcWindow' (static) + val7 := t.PtcWindow + startPos5 := dec.GetPosition() + for idx1 := range 96 { + val8 := val7[idx1] + if err = sszutils.DecodeUint64Slice(dec, val8[:512]); err != nil { + return sszutils.ErrorWithPathf(err, "PtcWindow[%d]", idx1) + } + if dec.GetPosition() != startPos5+int(4096*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos5+int(4096*(idx1+1))), "PtcWindow[%d]", idx1) + } + val7[idx1] = val8 + } + t.PtcWindow = val7 + } + { // Field #7 'HistoricalRoots' (dynamic) + if dec.GetPosition() != startPos0+int(offset7) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset7)), "HistoricalRoots") + } + dec.PushLimit(int(offset9 - offset7)) + val9 := t.HistoricalRoots + sszLen := dec.GetLength() + itemCount := sszLen / 32 + if sszLen%32 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 32), "HistoricalRoots") + } + if itemCount > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16777216), "HistoricalRoots") + } + val9 = sszutils.ExpandSlice(val9, itemCount) + startPos6 := dec.GetPosition() + for idx1 := range itemCount { + val9[idx1] = sszutils.ExpandSlice(val9[idx1], 32) + if _, err = dec.DecodeBytes(val9[idx1][:32]); err != nil { + return err + } + if dec.GetPosition() != startPos6+int(32*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos6+int(32*(idx1+1))), "HistoricalRoots[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "HistoricalRoots") + } + t.HistoricalRoots = val9 + } + { // Field #9 'Eth1DataVotes' (dynamic) + if dec.GetPosition() != startPos0+int(offset9) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset9)), "Eth1DataVotes") + } + dec.PushLimit(int(offset11 - offset9)) + val10 := t.Eth1DataVotes + sszLen := dec.GetLength() + itemCount := sszLen / 72 + if sszLen%72 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 72), "Eth1DataVotes") + } + if itemCount > 2048 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 2048), "Eth1DataVotes") + } + val10 = sszutils.ExpandSlice(val10, itemCount) + startPos7 := dec.GetPosition() + for idx1 := range itemCount { + if val10[idx1] == nil { + val10[idx1] = new(generic.Eth1Data) + } + if err = val10[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Eth1DataVotes[%d]", idx1) + } + if dec.GetPosition() != startPos7+int(72*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos7+int(72*(idx1+1))), "Eth1DataVotes[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Eth1DataVotes") + } + t.Eth1DataVotes = val10 + } + { // Field #11 'Validators' (dynamic) + if dec.GetPosition() != startPos0+int(offset11) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset11)), "Validators") + } + dec.PushLimit(int(offset12 - offset11)) + val11 := t.Validators + sszLen := dec.GetLength() + itemCount := sszLen / 121 + if sszLen%121 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 121), "Validators") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Validators") + } + val11 = sszutils.ExpandSlice(val11, itemCount) + startPos8 := dec.GetPosition() + for idx1 := range itemCount { + if val11[idx1] == nil { + val11[idx1] = new(generic.Validator) + } + if err = val11[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Validators[%d]", idx1) + } + if dec.GetPosition() != startPos8+int(121*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos8+int(121*(idx1+1))), "Validators[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Validators") + } + t.Validators = val11 + } + { // Field #12 'Balances' (dynamic) + if dec.GetPosition() != startPos0+int(offset12) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset12)), "Balances") + } + dec.PushLimit(int(offset15 - offset12)) + val12 := t.Balances + sszLen := dec.GetLength() + itemCount := sszLen / 8 + if sszLen%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 8), "Balances") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Balances") + } + val12 = sszutils.ExpandSlice(val12, itemCount) + if err = sszutils.DecodeUint64Slice(dec, val12); err != nil { + return sszutils.ErrorWithPath(err, "Balances") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Balances") + } + t.Balances = val12 + } + { // Field #15 'PreviousEpochParticipation' (dynamic) + if dec.GetPosition() != startPos0+int(offset15) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset15)), "PreviousEpochParticipation") + } + dec.PushLimit(int(offset16 - offset15)) + val13 := t.PreviousEpochParticipation + if dec.GetLength() > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(dec.GetLength(), 1099511627776), "PreviousEpochParticipation") + } + listLen := dec.GetLength() + val13 = sszutils.ExpandSlice(val13, listLen) + if _, err = dec.DecodeBytes(val13[:listLen]); err != nil { + return sszutils.ErrorWithPath(err, "PreviousEpochParticipation") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PreviousEpochParticipation") + } + t.PreviousEpochParticipation = val13 + } + { // Field #16 'CurrentEpochParticipation' (dynamic) + if dec.GetPosition() != startPos0+int(offset16) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset16)), "CurrentEpochParticipation") + } + dec.PushLimit(int(offset21 - offset16)) + val14 := t.CurrentEpochParticipation + if dec.GetLength() > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(dec.GetLength(), 1099511627776), "CurrentEpochParticipation") + } + listLen := dec.GetLength() + val14 = sszutils.ExpandSlice(val14, listLen) + if _, err = dec.DecodeBytes(val14[:listLen]); err != nil { + return sszutils.ErrorWithPath(err, "CurrentEpochParticipation") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "CurrentEpochParticipation") + } + t.CurrentEpochParticipation = val14 + } + { // Field #21 'InactivityScores' (dynamic) + if dec.GetPosition() != startPos0+int(offset21) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset21)), "InactivityScores") + } + dec.PushLimit(int(offset27 - offset21)) + val15 := t.InactivityScores + sszLen := dec.GetLength() + itemCount := sszLen / 8 + if sszLen%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 8), "InactivityScores") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "InactivityScores") + } + val15 = sszutils.ExpandSlice(val15, itemCount) + if err = sszutils.DecodeUint64Slice(dec, val15); err != nil { + return sszutils.ErrorWithPath(err, "InactivityScores") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "InactivityScores") + } + t.InactivityScores = val15 + } + { // Field #27 'HistoricalSummaries' (dynamic) + if dec.GetPosition() != startPos0+int(offset27) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset27)), "HistoricalSummaries") + } + dec.PushLimit(int(offset34 - offset27)) + val16 := t.HistoricalSummaries + sszLen := dec.GetLength() + itemCount := sszLen / 64 + if sszLen%64 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 64), "HistoricalSummaries") + } + if itemCount > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16777216), "HistoricalSummaries") + } + val16 = sszutils.ExpandSlice(val16, itemCount) + startPos9 := dec.GetPosition() + for idx1 := range itemCount { + if val16[idx1] == nil { + val16[idx1] = new(generic.HistoricalSummary) + } + if err = val16[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "HistoricalSummaries[%d]", idx1) + } + if dec.GetPosition() != startPos9+int(64*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos9+int(64*(idx1+1))), "HistoricalSummaries[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "HistoricalSummaries") + } + t.HistoricalSummaries = val16 + } + { // Field #34 'PendingDeposits' (dynamic) + if dec.GetPosition() != startPos0+int(offset34) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset34)), "PendingDeposits") + } + dec.PushLimit(int(offset35 - offset34)) + val17 := t.PendingDeposits + sszLen := dec.GetLength() + itemCount := sszLen / 192 + if sszLen%192 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 192), "PendingDeposits") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "PendingDeposits") + } + val17 = sszutils.ExpandSlice(val17, itemCount) + startPos10 := dec.GetPosition() + for idx1 := range itemCount { + if val17[idx1] == nil { + val17[idx1] = new(generic.PendingDeposit) + } + if err = val17[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "PendingDeposits[%d]", idx1) + } + if dec.GetPosition() != startPos10+int(192*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos10+int(192*(idx1+1))), "PendingDeposits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PendingDeposits") + } + t.PendingDeposits = val17 + } + { // Field #35 'PendingPartialWithdrawals' (dynamic) + if dec.GetPosition() != startPos0+int(offset35) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset35)), "PendingPartialWithdrawals") + } + dec.PushLimit(int(offset36 - offset35)) + val18 := t.PendingPartialWithdrawals + sszLen := dec.GetLength() + itemCount := sszLen / 24 + if sszLen%24 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 24), "PendingPartialWithdrawals") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "PendingPartialWithdrawals") + } + val18 = sszutils.ExpandSlice(val18, itemCount) + startPos11 := dec.GetPosition() + for idx1 := range itemCount { + if val18[idx1] == nil { + val18[idx1] = new(generic.PendingPartialWithdrawal) + } + if err = val18[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "PendingPartialWithdrawals[%d]", idx1) + } + if dec.GetPosition() != startPos11+int(24*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos11+int(24*(idx1+1))), "PendingPartialWithdrawals[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PendingPartialWithdrawals") + } + t.PendingPartialWithdrawals = val18 + } + { // Field #36 'PendingConsolidations' (dynamic) + if dec.GetPosition() != startPos0+int(offset36) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset36)), "PendingConsolidations") + } + dec.PushLimit(int(offset38 - offset36)) + val19 := t.PendingConsolidations + sszLen := dec.GetLength() + itemCount := sszLen / 16 + if sszLen%16 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 16), "PendingConsolidations") + } + if itemCount > 262144 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 262144), "PendingConsolidations") + } + val19 = sszutils.ExpandSlice(val19, itemCount) + startPos12 := dec.GetPosition() + for idx1 := range itemCount { + if val19[idx1] == nil { + val19[idx1] = new(generic.PendingConsolidation) + } + if err = val19[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "PendingConsolidations[%d]", idx1) + } + if dec.GetPosition() != startPos12+int(16*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos12+int(16*(idx1+1))), "PendingConsolidations[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PendingConsolidations") + } + t.PendingConsolidations = val19 + } + { // Field #38 'Builders' (dynamic) + if dec.GetPosition() != startPos0+int(offset38) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset38)), "Builders") + } + dec.PushLimit(int(offset42 - offset38)) + val20 := t.Builders + sszLen := dec.GetLength() + itemCount := sszLen / 93 + if sszLen%93 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 93), "Builders") + } + if itemCount > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1099511627776), "Builders") + } + val20 = sszutils.ExpandSlice(val20, itemCount) + startPos13 := dec.GetPosition() + for idx1 := range itemCount { + if val20[idx1] == nil { + val20[idx1] = new(Builder) + } + if err = val20[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Builders[%d]", idx1) + } + if dec.GetPosition() != startPos13+int(93*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos13+int(93*(idx1+1))), "Builders[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Builders") + } + t.Builders = val20 + } + { // Field #42 'BuilderPendingWithdrawals' (dynamic) + if dec.GetPosition() != startPos0+int(offset42) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset42)), "BuilderPendingWithdrawals") + } + dec.PushLimit(int(offset43 - offset42)) + val21 := t.BuilderPendingWithdrawals + sszLen := dec.GetLength() + itemCount := sszLen / 36 + if sszLen%36 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 36), "BuilderPendingWithdrawals") + } + if itemCount > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 134217728), "BuilderPendingWithdrawals") + } + val21 = sszutils.ExpandSlice(val21, itemCount) + startPos14 := dec.GetPosition() + for idx1 := range itemCount { + if val21[idx1] == nil { + val21[idx1] = new(BuilderPendingWithdrawal) + } + if err = val21[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingWithdrawals[%d]", idx1) + } + if dec.GetPosition() != startPos14+int(36*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos14+int(36*(idx1+1))), "BuilderPendingWithdrawals[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "BuilderPendingWithdrawals") + } + t.BuilderPendingWithdrawals = val21 + } + { // Field #43 'LatestExecutionPayloadBid' (dynamic) + if dec.GetPosition() != startPos0+int(offset43) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset43)), "LatestExecutionPayloadBid") + } + dec.PushLimit(int(offset44 - offset43)) + val22 := t.LatestExecutionPayloadBid + if val22 == nil { + val22 = new(ExecutionPayloadBid) + } + if err = val22.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "LatestExecutionPayloadBid") + } + t.LatestExecutionPayloadBid = val22 + } + { // Field #44 'PayloadExpectedWithdrawals' (dynamic) + if dec.GetPosition() != startPos0+int(offset44) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset44)), "PayloadExpectedWithdrawals") + } + dec.PushLimit(int(maxOffset - offset44)) + val23 := t.PayloadExpectedWithdrawals + sszLen := dec.GetLength() + itemCount := sszLen / 44 + if sszLen%44 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 44), "PayloadExpectedWithdrawals") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "PayloadExpectedWithdrawals") + } + val23 = sszutils.ExpandSlice(val23, itemCount) + startPos15 := dec.GetPosition() + for idx1 := range itemCount { + if val23[idx1] == nil { + val23[idx1] = new(generic.Withdrawal) + } + if err = val23[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadExpectedWithdrawals[%d]", idx1) + } + if dec.GetPosition() != startPos15+int(44*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos15+int(44*(idx1+1))), "PayloadExpectedWithdrawals[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PayloadExpectedWithdrawals") + } + t.PayloadExpectedWithdrawals = val23 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *BeaconState using dynamic specifications. +func (t *BeaconState) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(BeaconState) + } + // Field #0 'GenesisTime' static (8 bytes) + // Field #1 'GenesisValidatorsRoot' static (32 bytes) + // Field #2 'Slot' static (8 bytes) + // Field #3 'Fork' static (16 bytes) + // Field #4 'LatestBlockHeader' static (112 bytes) + // Field #5 'BlockRoots' static (262144 bytes) + // Field #6 'StateRoots' static (262144 bytes) + // Field #7 'HistoricalRoots' offset (4 bytes) + // Field #8 'Eth1Data' static (72 bytes) + // Field #9 'Eth1DataVotes' offset (4 bytes) + // Field #10 'Eth1DepositIndex' static (8 bytes) + // Field #11 'Validators' offset (4 bytes) + // Field #12 'Balances' offset (4 bytes) + // Field #13 'RandaoMixes' static (2097152 bytes) + // Field #14 'Slashings' static (65536 bytes) + // Field #15 'PreviousEpochParticipation' offset (4 bytes) + // Field #16 'CurrentEpochParticipation' offset (4 bytes) + // Field #17 'JustificationBits' static (1 bytes) + // Field #18 'PreviousJustifiedCheckpoint' static (40 bytes) + // Field #19 'CurrentJustifiedCheckpoint' static (40 bytes) + // Field #20 'FinalizedCheckpoint' static (40 bytes) + // Field #21 'InactivityScores' offset (4 bytes) + // Field #22 'CurrentSyncCommittee' static (24624 bytes) + // Field #23 'NextSyncCommittee' static (24624 bytes) + // Field #24 'LatestBlockHash' static (32 bytes) + // Field #25 'NextWithdrawalIndex' static (8 bytes) + // Field #26 'NextWithdrawalValidatorIndex' static (8 bytes) + // Field #27 'HistoricalSummaries' offset (4 bytes) + // Field #28 'DepositRequestsStartIndex' static (8 bytes) + // Field #29 'DepositBalanceToConsume' static (8 bytes) + // Field #30 'ExitBalanceToConsume' static (8 bytes) + // Field #31 'EarliestExitEpoch' static (8 bytes) + // Field #32 'ConsolidationBalanceToConsume' static (8 bytes) + // Field #33 'EarliestConsolidationEpoch' static (8 bytes) + // Field #34 'PendingDeposits' offset (4 bytes) + // Field #35 'PendingPartialWithdrawals' offset (4 bytes) + // Field #36 'PendingConsolidations' offset (4 bytes) + // Field #37 'ProposerLookahead' static (512 bytes) + // Field #38 'Builders' offset (4 bytes) + // Field #39 'NextWithdrawalBuilderIndex' static (8 bytes) + // Field #40 'ExecutionPayloadAvailability' static (1024 bytes) + // Field #41 'BuilderPendingPayments' static (3328 bytes) + // Field #42 'BuilderPendingWithdrawals' offset (4 bytes) + // Field #43 'LatestExecutionPayloadBid' offset (4 bytes) + // Field #44 'PayloadExpectedWithdrawals' offset (4 bytes) + // Field #45 'PtcWindow' static (393216 bytes) + size += 3134845 + { // Dynamic field #7 'HistoricalRoots' + size += len(t.HistoricalRoots) * 32 + } + { // Dynamic field #9 'Eth1DataVotes' + size += len(t.Eth1DataVotes) * 72 + } + { // Dynamic field #11 'Validators' + size += len(t.Validators) * 121 + } + { // Dynamic field #12 'Balances' + size += len(t.Balances) * 8 + } + { // Dynamic field #15 'PreviousEpochParticipation' + size += len(t.PreviousEpochParticipation) + } + { // Dynamic field #16 'CurrentEpochParticipation' + size += len(t.CurrentEpochParticipation) + } + { // Dynamic field #21 'InactivityScores' + size += len(t.InactivityScores) * 8 + } + { // Dynamic field #27 'HistoricalSummaries' + size += len(t.HistoricalSummaries) * 64 + } + { // Dynamic field #34 'PendingDeposits' + size += len(t.PendingDeposits) * 192 + } + { // Dynamic field #35 'PendingPartialWithdrawals' + size += len(t.PendingPartialWithdrawals) * 24 + } + { // Dynamic field #36 'PendingConsolidations' + size += len(t.PendingConsolidations) * 16 + } + { // Dynamic field #38 'Builders' + size += len(t.Builders) * 93 + } + { // Dynamic field #42 'BuilderPendingWithdrawals' + size += len(t.BuilderPendingWithdrawals) * 36 + } + { // Dynamic field #43 'LatestExecutionPayloadBid' + size += t.LatestExecutionPayloadBid.SizeSSZDyn(ds) + } + { // Dynamic field #44 'PayloadExpectedWithdrawals' + size += len(t.PayloadExpectedWithdrawals) * 44 + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BeaconState using dynamic specifications. +func (t *BeaconState) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BeaconState using dynamic specifications and the given hash walker. +func (t *BeaconState) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(BeaconState) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'GenesisTime' + hh.PutUint64(t.GenesisTime) + } + { // Field #1 'GenesisValidatorsRoot' + vlen := len(t.GenesisValidatorsRoot) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "GenesisValidatorsRoot") + } + val := t.GenesisValidatorsRoot[:] + if vlen < 32 { + val = sszutils.AppendZeroPadding(val, (32-vlen)*1) + } + hh.PutBytes(val[:32]) + } + { // Field #2 'Slot' + hh.PutUint64(t.Slot) + } + { // Field #3 'Fork' + t := t.Fork + if t == nil { + t = new(generic.Fork) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Fork") + } + } + { // Field #4 'LatestBlockHeader' + t := t.LatestBlockHeader + if t == nil { + t = new(generic.BeaconBlockHeader) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "LatestBlockHeader") + } + } + { // Field #5 'BlockRoots' + t := &t.BlockRoots + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val1 *[32]byte + for idx1 := range 8192 { + if idx1 < 8192 { + val1 = &t[idx1] + } else if idx1 == 8192 { + val1 = new([32]byte) + } + hh.PutBytes(val1[:32]) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.Merkleize(idx) + } + { // Field #6 'StateRoots' + t := &t.StateRoots + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val2 *[32]byte + for idx1 := range 8192 { + if idx1 < 8192 { + val2 = &t[idx1] + } else if idx1 == 8192 { + val2 = new([32]byte) + } + hh.PutBytes(val2[:32]) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.Merkleize(idx) + } + { // Field #7 'HistoricalRoots' + t := t.HistoricalRoots + vlen := uint64(len(t)) + if vlen > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalRoots") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + for idx1 := range int(vlen) { + vlen := len(t[idx1]) + if vlen > 32 { + return sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "HistoricalRoots[%d]", idx1) + } + val := t[idx1][:] + if vlen < 32 { + val = sszutils.AppendZeroPadding(val, (32-vlen)*1) + } + hh.PutBytes(val[:32]) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeWithMixin(idx, vlen, sszutils.CalculateLimit(16777216, vlen, 32)) + } + { // Field #8 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + } + { // Field #9 'Eth1DataVotes' + t := t.Eth1DataVotes + vlen := uint64(len(t)) + if vlen > 2048 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2048), "Eth1DataVotes") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.Eth1Data) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Eth1DataVotes[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeWithMixin(idx, vlen, sszutils.CalculateLimit(2048, vlen, 32)) + } + { // Field #10 'Eth1DepositIndex' + hh.PutUint64(t.Eth1DepositIndex) + } + { // Field #11 'Validators' + t := t.Validators + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Validators") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.Validator) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Validators[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #12 'Balances' + t := t.Balances + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Balances") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + sszutils.HashUint64Slice(hh, t) + hh.FillUpTo32() + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #13 'RandaoMixes' + t := t.RandaoMixes + vlen := len(t) + if vlen > 65536 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 65536), "RandaoMixes") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val3, val3Empty []byte + for idx1 := range 65536 { + if idx1 < vlen { + val3 = t[idx1] + } else if idx1 == vlen { + val3 = val3Empty + } + vlen := len(val3) + if vlen > 32 { + return sszutils.ErrorWithPathf(sszutils.ErrVectorLengthFn(vlen, 32), "RandaoMixes[%d]", idx1) + } + val := val3[:] + if vlen < 32 { + val = sszutils.AppendZeroPadding(val, (32-vlen)*1) + } + hh.PutBytes(val[:32]) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.Merkleize(idx) + } + { // Field #14 'Slashings' + t := t.Slashings + vlen := len(t) + if vlen > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8192), "Slashings") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val4, val4Empty uint64 + for idx1 := range 8192 { + if idx1 < vlen { + val4 = t[idx1] + } else if idx1 == vlen { + val4 = val4Empty + } + hh.AppendUint64(val4) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.FillUpTo32() + hh.Merkleize(idx) + } + { // Field #15 'PreviousEpochParticipation' + t := t.PreviousEpochParticipation + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "PreviousEpochParticipation") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + hh.AppendBytes32(t[:]) + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #16 'CurrentEpochParticipation' + t := t.CurrentEpochParticipation + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "CurrentEpochParticipation") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + hh.AppendBytes32(t[:]) + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #17 'JustificationBits' + hh.PutBytes(t.JustificationBits[:1]) + } + { // Field #18 'PreviousJustifiedCheckpoint' + t := t.PreviousJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "PreviousJustifiedCheckpoint") + } + } + { // Field #19 'CurrentJustifiedCheckpoint' + t := t.CurrentJustifiedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "CurrentJustifiedCheckpoint") + } + } + { // Field #20 'FinalizedCheckpoint' + t := t.FinalizedCheckpoint + if t == nil { + t = new(generic.Checkpoint) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "FinalizedCheckpoint") + } + } + { // Field #21 'InactivityScores' + t := t.InactivityScores + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "InactivityScores") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + sszutils.HashUint64Slice(hh, t) + hh.FillUpTo32() + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #22 'CurrentSyncCommittee' + t := t.CurrentSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "CurrentSyncCommittee") + } + } + { // Field #23 'NextSyncCommittee' + t := t.NextSyncCommittee + if t == nil { + t = new(generic.SyncCommittee) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "NextSyncCommittee") + } + } + { // Field #24 'LatestBlockHash' + hh.PutBytes(t.LatestBlockHash[:32]) + } + { // Field #25 'NextWithdrawalIndex' + hh.PutUint64(t.NextWithdrawalIndex) + } + { // Field #26 'NextWithdrawalValidatorIndex' + hh.PutUint64(t.NextWithdrawalValidatorIndex) + } + { // Field #27 'HistoricalSummaries' + t := t.HistoricalSummaries + vlen := uint64(len(t)) + if vlen > 16777216 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16777216), "HistoricalSummaries") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.HistoricalSummary) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "HistoricalSummaries[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeWithMixin(idx, vlen, sszutils.CalculateLimit(16777216, vlen, 32)) + } + { // Field #28 'DepositRequestsStartIndex' + hh.PutUint64(t.DepositRequestsStartIndex) + } + { // Field #29 'DepositBalanceToConsume' + hh.PutUint64(t.DepositBalanceToConsume) + } + { // Field #30 'ExitBalanceToConsume' + hh.PutUint64(t.ExitBalanceToConsume) + } + { // Field #31 'EarliestExitEpoch' + hh.PutUint64(t.EarliestExitEpoch) + } + { // Field #32 'ConsolidationBalanceToConsume' + hh.PutUint64(t.ConsolidationBalanceToConsume) + } + { // Field #33 'EarliestConsolidationEpoch' + hh.PutUint64(t.EarliestConsolidationEpoch) + } + { // Field #34 'PendingDeposits' + t := t.PendingDeposits + vlen := uint64(len(t)) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingDeposits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.PendingDeposit) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "PendingDeposits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #35 'PendingPartialWithdrawals' + t := t.PendingPartialWithdrawals + vlen := uint64(len(t)) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "PendingPartialWithdrawals") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.PendingPartialWithdrawal) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "PendingPartialWithdrawals[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #36 'PendingConsolidations' + t := t.PendingConsolidations + vlen := uint64(len(t)) + if vlen > 262144 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 262144), "PendingConsolidations") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.PendingConsolidation) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "PendingConsolidations[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #37 'ProposerLookahead' + t := t.ProposerLookahead + vlen := len(t) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "ProposerLookahead") + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val5, val5Empty uint64 + for idx1 := range 64 { + if idx1 < vlen { + val5 = t[idx1] + } else if idx1 == vlen { + val5 = val5Empty + } + hh.AppendUint64(val5) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.FillUpTo32() + hh.Merkleize(idx) + } + { // Field #38 'Builders' + t := t.Builders + vlen := uint64(len(t)) + if vlen > 1099511627776 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1099511627776), "Builders") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(Builder) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Builders[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #39 'NextWithdrawalBuilderIndex' + hh.PutUint64(t.NextWithdrawalBuilderIndex) + } + { // Field #40 'ExecutionPayloadAvailability' + vlen := len(t.ExecutionPayloadAvailability) + if vlen > 1024 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 1024), "ExecutionPayloadAvailability") + } + val := t.ExecutionPayloadAvailability[:] + if vlen < 1024 { + val = sszutils.AppendZeroPadding(val, (1024-vlen)*1) + } + hh.PutBytes(val[:1024]) + } + { // Field #41 'BuilderPendingPayments' + t := &t.BuilderPendingPayments + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val6 *BuilderPendingPayment + for idx1 := range 64 { + if idx1 < 64 { + val6 = t[idx1] + } else if idx1 == 64 { + val6 = new(BuilderPendingPayment) + } + if val6 == nil { + val6 = new(BuilderPendingPayment) + } + if err := val6.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingPayments[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.Merkleize(idx) + } + { // Field #42 'BuilderPendingWithdrawals' + t := t.BuilderPendingWithdrawals + vlen := uint64(len(t)) + if vlen > 134217728 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 134217728), "BuilderPendingWithdrawals") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderPendingWithdrawals[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #43 'LatestExecutionPayloadBid' + t := t.LatestExecutionPayloadBid + if t == nil { + t = new(ExecutionPayloadBid) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "LatestExecutionPayloadBid") + } + } + { // Field #44 'PayloadExpectedWithdrawals' + t := t.PayloadExpectedWithdrawals + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "PayloadExpectedWithdrawals") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.Withdrawal) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadExpectedWithdrawals[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #45 'PtcWindow' + t := &t.PtcWindow + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val7 *[512]uint64 + for idx1 := range 96 { + if idx1 < 96 { + val7 = &t[idx1] + } else if idx1 == 96 { + val7 = new([512]uint64) + } + idx := hh.StartTree(sszutils.TreeTypeBinary) + var val8, val8Empty uint64 + for idx2 := range 512 { + if idx2 < 512 { + val8 = val7[idx2] + } else if idx2 == 512 { + val8 = val8Empty + } + hh.AppendUint64(val8) + if (idx2+1)%256 == 0 { + hh.Collapse() + } + } + hh.FillUpTo32() + hh.Merkleize(idx) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.Merkleize(idx) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f}) + return nil +} + +// MarshalSSZDyn marshals the *SignedBeaconBlock to SSZ-encoded bytes using dynamic specifications. +func (t *SignedBeaconBlock) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(SignedBeaconBlock) + } + dstlen := len(dst) + // Offset Field #0 'Block' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #1 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + dst = append(dst, t.Signature[:vlen]...) + if vlen < 96 { + dst = sszutils.AppendZeroPadding(dst, (96-vlen)*1) + } + } + { // Dynamic Field #0 'Block' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.Block + if t == nil { + t = new(BeaconBlock) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Block") + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *SignedBeaconBlock to the given SSZ encoder using dynamic specifications. +func (t *SignedBeaconBlock) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t *BeaconBlock) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for *BeaconBlock + ctx.sizeFn1 = func(ctx *encoderCtx, t *BeaconBlock) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + if t == nil { + t = new(SignedBeaconBlock) + } + dstlen := enc.GetPosition() + dynoff := uint32(100) + // Offset #0 'Block' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Block)) + } + { // Field #1 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + enc.EncodeBytes(t.Signature[:vlen]) + if vlen < 96 { + enc.EncodeZeroPadding((96 - vlen) * 1) + } + } + { // Dynamic Field #0 'Block' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.Block + if t == nil { + t = new(BeaconBlock) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Block") + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *SignedBeaconBlock from SSZ-encoded bytes using dynamic specifications. +func (t *SignedBeaconBlock) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 100 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 100) + } + // Field #0 'Block' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 100 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 100), "Block:o") + } + { // Field #1 'Signature' (static) + buf := buf[4:100] + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + copy(t.Signature[:], buf) + } + { // Field #0 'Block' (dynamic) + buf := buf[offset0:] + if t.Block == nil { + t.Block = new(BeaconBlock) + } + if err = t.Block.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Block") + } + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *SignedBeaconBlock from the given SSZ decoder using dynamic specifications. +func (t *SignedBeaconBlock) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(100) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(100)) + } + // Field #0 'Block' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Block") + } + if offset0 != uint32(100) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 100), "Block") + } + // Field #1 'Signature' (static) + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + { // Field #0 'Block' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "Block") + } + dec.PushLimit(int(maxOffset - offset0)) + val1 := t.Block + if val1 == nil { + val1 = new(BeaconBlock) + } + if err = val1.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Block") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Block") + } + t.Block = val1 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *SignedBeaconBlock using dynamic specifications. +func (t *SignedBeaconBlock) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(SignedBeaconBlock) + } + // Field #0 'Block' offset (4 bytes) + // Field #1 'Signature' static (96 bytes) + size += 100 + { // Dynamic field #0 'Block' + size += t.Block.SizeSSZDyn(ds) + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *SignedBeaconBlock using dynamic specifications. +func (t *SignedBeaconBlock) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *SignedBeaconBlock using dynamic specifications and the given hash walker. +func (t *SignedBeaconBlock) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(SignedBeaconBlock) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Block' + t := t.Block + if t == nil { + t = new(BeaconBlock) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Block") + } + } + { // Field #1 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + val := t.Signature[:] + if vlen < 96 { + val = sszutils.AppendZeroPadding(val, (96-vlen)*1) + } + hh.PutBytes(val[:96]) + } + hh.Merkleize(idx) + return nil +} + +// MarshalSSZDyn marshals the *BeaconBlock to SSZ-encoded bytes using dynamic specifications. +func (t *BeaconBlock) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(BeaconBlock) + } + dstlen := len(dst) + { // Static Field #0 'Slot' + dst = binary.LittleEndian.AppendUint64(dst, t.Slot) + } + { // Static Field #1 'ProposerIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.ProposerIndex) + } + { // Static Field #2 'ParentRoot' + dst = append(dst, t.ParentRoot[:32]...) + } + { // Static Field #3 'StateRoot' + dst = append(dst, t.StateRoot[:32]...) + } + // Offset Field #4 'Body' + dst = append(dst, 0, 0, 0, 0) + { // Dynamic Field #4 'Body' + binary.LittleEndian.PutUint32(dst[dstlen+80:], uint32(len(dst)-dstlen)) + t := t.Body + if t == nil { + t = new(BeaconBlockBody) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Body") + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *BeaconBlock to the given SSZ encoder using dynamic specifications. +func (t *BeaconBlock) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t *BeaconBlockBody) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for *BeaconBlockBody + ctx.sizeFn1 = func(ctx *encoderCtx, t *BeaconBlockBody) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + if t == nil { + t = new(BeaconBlock) + } + dstlen := enc.GetPosition() + dynoff := uint32(84) + { // Field #0 'Slot' + enc.EncodeUint64(t.Slot) + } + { // Field #1 'ProposerIndex' + enc.EncodeUint64(t.ProposerIndex) + } + { // Field #2 'ParentRoot' + enc.EncodeBytes(t.ParentRoot[:32]) + } + { // Field #3 'StateRoot' + enc.EncodeBytes(t.StateRoot[:32]) + } + // Offset #4 'Body' + offset4 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Body)) + } + { // Dynamic Field #4 'Body' + if canSeek { + enc.EncodeOffsetAt(offset4, uint32(enc.GetPosition()-dstlen)) + } + t := t.Body + if t == nil { + t = new(BeaconBlockBody) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Body") + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BeaconBlock from SSZ-encoded bytes using dynamic specifications. +func (t *BeaconBlock) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 84 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 84) + } + { // Field #0 'Slot' (static) + buf := buf[0:8] + t.Slot = binary.LittleEndian.Uint64(buf) + } + { // Field #1 'ProposerIndex' (static) + buf := buf[8:16] + t.ProposerIndex = binary.LittleEndian.Uint64(buf) + } + { // Field #2 'ParentRoot' (static) + buf := buf[16:48] + copy(t.ParentRoot[:], buf) + } + { // Field #3 'StateRoot' (static) + buf := buf[48:80] + copy(t.StateRoot[:], buf) + } + // Field #4 'Body' (offset) + offset4 := int(binary.LittleEndian.Uint32(buf[80:84])) + if offset4 != 84 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset4, 84), "Body:o") + } + { // Field #4 'Body' (dynamic) + buf := buf[offset4:] + if t.Body == nil { + t.Body = new(BeaconBlockBody) + } + if err = t.Body.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Body") + } + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *BeaconBlock from the given SSZ decoder using dynamic specifications. +func (t *BeaconBlock) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(84) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(84)) + } + // Field #0 'Slot' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Slot") + } else { + t.Slot = val + } + // Field #1 'ProposerIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "ProposerIndex") + } else { + t.ProposerIndex = val + } + // Field #2 'ParentRoot' (static) + if _, err = dec.DecodeBytes(t.ParentRoot[:32]); err != nil { + return err + } + // Field #3 'StateRoot' (static) + if _, err = dec.DecodeBytes(t.StateRoot[:32]); err != nil { + return err + } + // Field #4 'Body' (offset) + offset4, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Body") + } + if offset4 != uint32(84) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset4, 84), "Body") + } + { // Field #4 'Body' (dynamic) + if dec.GetPosition() != startPos0+int(offset4) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset4)), "Body") + } + dec.PushLimit(int(maxOffset - offset4)) + val1 := t.Body + if val1 == nil { + val1 = new(BeaconBlockBody) + } + if err = val1.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Body") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Body") + } + t.Body = val1 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *BeaconBlock using dynamic specifications. +func (t *BeaconBlock) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(BeaconBlock) + } + // Field #0 'Slot' static (8 bytes) + // Field #1 'ProposerIndex' static (8 bytes) + // Field #2 'ParentRoot' static (32 bytes) + // Field #3 'StateRoot' static (32 bytes) + // Field #4 'Body' offset (4 bytes) + size += 84 + { // Dynamic field #4 'Body' + size += t.Body.SizeSSZDyn(ds) + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BeaconBlock using dynamic specifications. +func (t *BeaconBlock) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BeaconBlock using dynamic specifications and the given hash walker. +func (t *BeaconBlock) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(BeaconBlock) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Slot' + hh.PutUint64(t.Slot) + } + { // Field #1 'ProposerIndex' + hh.PutUint64(t.ProposerIndex) + } + { // Field #2 'ParentRoot' + hh.PutBytes(t.ParentRoot[:32]) + } + { // Field #3 'StateRoot' + hh.PutBytes(t.StateRoot[:32]) + } + { // Field #4 'Body' + t := t.Body + if t == nil { + t = new(BeaconBlockBody) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Body") + } + } + hh.Merkleize(idx) + return nil +} + +// MarshalSSZDyn marshals the *BeaconBlockBody to SSZ-encoded bytes using dynamic specifications. +func (t *BeaconBlockBody) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + zeroBytes := sszutils.ZeroBytes() + if t == nil { + t = new(BeaconBlockBody) + } + dstlen := len(dst) + { // Static Field #0 'RandaoReveal' + vlen := len(t.RandaoReveal) + if vlen > 96 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "RandaoReveal") + } + dst = append(dst, t.RandaoReveal[:vlen]...) + if vlen < 96 { + dst = sszutils.AppendZeroPadding(dst, (96-vlen)*1) + } + } + { // Static Field #1 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Eth1Data") + } + } + { // Static Field #2 'Graffiti' + dst = append(dst, t.Graffiti[:32]...) + } + // Offset Field #3 'ProposerSlashings' + // Offset Field #4 'AttesterSlashings' + // Offset Field #5 'Attestations' + // Offset Field #6 'Deposits' + // Offset Field #7 'VoluntaryExits' + dst = append(dst, zeroBytes[:20]...) + { // Static Field #8 'SyncAggregate' + t := t.SyncAggregate + if t == nil { + t = new(generic.SyncAggregate) + } + if dst, err = t.MarshalSSZTo(dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "SyncAggregate") + } + } + // Offset Field #9 'BlsToExecutionChanges' + // Offset Field #10 'SignedExecutionPayloadBid' + // Offset Field #11 'PayloadAttestations' + // Offset Field #12 'ParentExecutionRequests' + dst = append(dst, zeroBytes[:16]...) + { // Dynamic Field #3 'ProposerSlashings' + binary.LittleEndian.PutUint32(dst[dstlen+200:], uint32(len(dst)-dstlen)) + t := t.ProposerSlashings + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "ProposerSlashings") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.ProposerSlashing) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "ProposerSlashings[%d]", idx1) + } + } + } + { // Dynamic Field #4 'AttesterSlashings' + binary.LittleEndian.PutUint32(dst[dstlen+204:], uint32(len(dst)-dstlen)) + t := t.AttesterSlashings + vlen := len(t) + if vlen > 1 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1), "AttesterSlashings") + } + dstlen := len(dst) + dst = sszutils.AppendZeroPadding(dst, vlen*4) + for idx1 := range vlen { + binary.LittleEndian.PutUint32(dst[dstlen+(idx1*4):], uint32(len(dst)-dstlen)) + t := t[idx1] + if t == nil { + t = new(AttesterSlashing) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "AttesterSlashings[%d]", idx1) + } + } + } + { // Dynamic Field #5 'Attestations' + binary.LittleEndian.PutUint32(dst[dstlen+208:], uint32(len(dst)-dstlen)) + t := t.Attestations + vlen := len(t) + if vlen > 8 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8), "Attestations") + } + dstlen := len(dst) + dst = sszutils.AppendZeroPadding(dst, vlen*4) + for idx1 := range vlen { + binary.LittleEndian.PutUint32(dst[dstlen+(idx1*4):], uint32(len(dst)-dstlen)) + t := t[idx1] + if t == nil { + t = new(Attestation) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Attestations[%d]", idx1) + } + } + } + { // Dynamic Field #6 'Deposits' + binary.LittleEndian.PutUint32(dst[dstlen+212:], uint32(len(dst)-dstlen)) + t := t.Deposits + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Deposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Deposit) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + } + { // Dynamic Field #7 'VoluntaryExits' + binary.LittleEndian.PutUint32(dst[dstlen+216:], uint32(len(dst)-dstlen)) + t := t.VoluntaryExits + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "VoluntaryExits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.SignedVoluntaryExit) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "VoluntaryExits[%d]", idx1) + } + } + } + { // Dynamic Field #9 'BlsToExecutionChanges' + binary.LittleEndian.PutUint32(dst[dstlen+380:], uint32(len(dst)-dstlen)) + t := t.BlsToExecutionChanges + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BlsToExecutionChanges") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.SignedBLSToExecutionChange) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "BlsToExecutionChanges[%d]", idx1) + } + } + } + { // Dynamic Field #10 'SignedExecutionPayloadBid' + binary.LittleEndian.PutUint32(dst[dstlen+384:], uint32(len(dst)-dstlen)) + t := t.SignedExecutionPayloadBid + if t == nil { + t = new(SignedExecutionPayloadBid) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + } + { // Dynamic Field #11 'PayloadAttestations' + binary.LittleEndian.PutUint32(dst[dstlen+388:], uint32(len(dst)-dstlen)) + t := t.PayloadAttestations + vlen := len(t) + if vlen > 4 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4), "PayloadAttestations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(PayloadAttestation) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "PayloadAttestations[%d]", idx1) + } + } + } + { // Dynamic Field #12 'ParentExecutionRequests' + binary.LittleEndian.PutUint32(dst[dstlen+392:], uint32(len(dst)-dstlen)) + t := t.ParentExecutionRequests + if t == nil { + t = new(ExecutionRequests) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *BeaconBlockBody to the given SSZ encoder using dynamic specifications. +func (t *BeaconBlockBody) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t []*generic.ProposerSlashing) (size int) + sizeFn10 func(ctx *encoderCtx, t *AttesterSlashing) (size int) + sizeFn11 func(ctx *encoderCtx, t *Attestation) (size int) + sizeFn2 func(ctx *encoderCtx, t []*AttesterSlashing) (size int) + sizeFn3 func(ctx *encoderCtx, t []*Attestation) (size int) + sizeFn4 func(ctx *encoderCtx, t []*generic.Deposit) (size int) + sizeFn5 func(ctx *encoderCtx, t []*generic.SignedVoluntaryExit) (size int) + sizeFn6 func(ctx *encoderCtx, t []*generic.SignedBLSToExecutionChange) (size int) + sizeFn7 func(ctx *encoderCtx, t *SignedExecutionPayloadBid) (size int) + sizeFn8 func(ctx *encoderCtx, t []*PayloadAttestation) (size int) + sizeFn9 func(ctx *encoderCtx, t *ExecutionRequests) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for []*generic.ProposerSlashing + ctx.sizeFn1 = func(ctx *encoderCtx, t []*generic.ProposerSlashing) (size int) { + size += len(t) * 416 + return size + } + // size for []*AttesterSlashing + ctx.sizeFn2 = func(ctx *encoderCtx, t []*AttesterSlashing) (size int) { + vlen := len(t) + size += vlen * 4 // Offsets + for i1 := range vlen { + size += ctx.sizeFn10(ctx, t[i1]) + } + return size + } + // size for []*Attestation + ctx.sizeFn3 = func(ctx *encoderCtx, t []*Attestation) (size int) { + vlen := len(t) + size += vlen * 4 // Offsets + for i1 := range vlen { + size += ctx.sizeFn11(ctx, t[i1]) + } + return size + } + // size for []*generic.Deposit + ctx.sizeFn4 = func(ctx *encoderCtx, t []*generic.Deposit) (size int) { + size += len(t) * 1240 + return size + } + // size for []*generic.SignedVoluntaryExit + ctx.sizeFn5 = func(ctx *encoderCtx, t []*generic.SignedVoluntaryExit) (size int) { + size += len(t) * 112 + return size + } + // size for []*generic.SignedBLSToExecutionChange + ctx.sizeFn6 = func(ctx *encoderCtx, t []*generic.SignedBLSToExecutionChange) (size int) { + size += len(t) * 172 + return size + } + // size for *SignedExecutionPayloadBid + ctx.sizeFn7 = func(ctx *encoderCtx, t *SignedExecutionPayloadBid) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + // size for []*PayloadAttestation + ctx.sizeFn8 = func(ctx *encoderCtx, t []*PayloadAttestation) (size int) { + size += len(t) * 202 + return size + } + // size for *ExecutionRequests + ctx.sizeFn9 = func(ctx *encoderCtx, t *ExecutionRequests) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + // size for *AttesterSlashing + ctx.sizeFn10 = func(ctx *encoderCtx, t *AttesterSlashing) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + // size for *Attestation + ctx.sizeFn11 = func(ctx *encoderCtx, t *Attestation) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + if t == nil { + t = new(BeaconBlockBody) + } + dstlen := enc.GetPosition() + dynoff := uint32(396) + { // Field #0 'RandaoReveal' + vlen := len(t.RandaoReveal) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "RandaoReveal") + } + enc.EncodeBytes(t.RandaoReveal[:vlen]) + if vlen < 96 { + enc.EncodeZeroPadding((96 - vlen) * 1) + } + } + { // Field #1 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } else { + enc.SetBuffer(buf) + } + } + { // Field #2 'Graffiti' + enc.EncodeBytes(t.Graffiti[:32]) + } + // Offset #3 'ProposerSlashings' + offset3 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.ProposerSlashings)) + } + // Offset #4 'AttesterSlashings' + offset4 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn2(ctx, t.AttesterSlashings)) + } + // Offset #5 'Attestations' + offset5 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn3(ctx, t.Attestations)) + } + // Offset #6 'Deposits' + offset6 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn4(ctx, t.Deposits)) + } + // Offset #7 'VoluntaryExits' + offset7 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn5(ctx, t.VoluntaryExits)) + } + { // Field #8 'SyncAggregate' + t := t.SyncAggregate + if t == nil { + t = new(generic.SyncAggregate) + } + if buf, err := t.MarshalSSZTo(enc.GetBuffer()); err != nil { + return sszutils.ErrorWithPath(err, "SyncAggregate") + } else { + enc.SetBuffer(buf) + } + } + // Offset #9 'BlsToExecutionChanges' + offset9 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn6(ctx, t.BlsToExecutionChanges)) + } + // Offset #10 'SignedExecutionPayloadBid' + offset10 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn7(ctx, t.SignedExecutionPayloadBid)) + } + // Offset #11 'PayloadAttestations' + offset11 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn8(ctx, t.PayloadAttestations)) + } + // Offset #12 'ParentExecutionRequests' + offset12 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn9(ctx, t.ParentExecutionRequests)) + } + { // Dynamic Field #3 'ProposerSlashings' + if canSeek { + enc.EncodeOffsetAt(offset3, uint32(enc.GetPosition()-dstlen)) + } + t := t.ProposerSlashings + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "ProposerSlashings") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.ProposerSlashing) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "ProposerSlashings[%d]", idx1) + } + } + } + { // Dynamic Field #4 'AttesterSlashings' + if canSeek { + enc.EncodeOffsetAt(offset4, uint32(enc.GetPosition()-dstlen)) + } + t := t.AttesterSlashings + vlen := len(t) + if vlen > 1 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1), "AttesterSlashings") + } + dstlen := enc.GetPosition() + if canSeek { + enc.EncodeZeroPadding(vlen * 4) + } else if vlen > 0 { + offset := vlen * 4 + enc.EncodeOffset(uint32(offset)) + for i := range vlen - 1 { + offset += ctx.sizeFn10(ctx, t[i]) + enc.EncodeOffset(uint32(offset)) + } + } + for idx1 := range vlen { + if canSeek { + enc.EncodeOffsetAt(dstlen+(idx1*4), uint32(enc.GetPosition()-dstlen)) + } + t := t[idx1] + if t == nil { + t = new(AttesterSlashing) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "AttesterSlashings[%d]", idx1) + } + } + } + { // Dynamic Field #5 'Attestations' + if canSeek { + enc.EncodeOffsetAt(offset5, uint32(enc.GetPosition()-dstlen)) + } + t := t.Attestations + vlen := len(t) + if vlen > 8 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8), "Attestations") + } + dstlen := enc.GetPosition() + if canSeek { + enc.EncodeZeroPadding(vlen * 4) + } else if vlen > 0 { + offset := vlen * 4 + enc.EncodeOffset(uint32(offset)) + for i := range vlen - 1 { + offset += ctx.sizeFn11(ctx, t[i]) + enc.EncodeOffset(uint32(offset)) + } + } + for idx1 := range vlen { + if canSeek { + enc.EncodeOffsetAt(dstlen+(idx1*4), uint32(enc.GetPosition()-dstlen)) + } + t := t[idx1] + if t == nil { + t = new(Attestation) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Attestations[%d]", idx1) + } + } + } + { // Dynamic Field #6 'Deposits' + if canSeek { + enc.EncodeOffsetAt(offset6, uint32(enc.GetPosition()-dstlen)) + } + t := t.Deposits + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Deposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.Deposit) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + } + { // Dynamic Field #7 'VoluntaryExits' + if canSeek { + enc.EncodeOffsetAt(offset7, uint32(enc.GetPosition()-dstlen)) + } + t := t.VoluntaryExits + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "VoluntaryExits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.SignedVoluntaryExit) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "VoluntaryExits[%d]", idx1) + } + } + } + { // Dynamic Field #9 'BlsToExecutionChanges' + if canSeek { + enc.EncodeOffsetAt(offset9, uint32(enc.GetPosition()-dstlen)) + } + t := t.BlsToExecutionChanges + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BlsToExecutionChanges") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(generic.SignedBLSToExecutionChange) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "BlsToExecutionChanges[%d]", idx1) + } + } + } + { // Dynamic Field #10 'SignedExecutionPayloadBid' + if canSeek { + enc.EncodeOffsetAt(offset10, uint32(enc.GetPosition()-dstlen)) + } + t := t.SignedExecutionPayloadBid + if t == nil { + t = new(SignedExecutionPayloadBid) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + } + { // Dynamic Field #11 'PayloadAttestations' + if canSeek { + enc.EncodeOffsetAt(offset11, uint32(enc.GetPosition()-dstlen)) + } + t := t.PayloadAttestations + vlen := len(t) + if vlen > 4 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4), "PayloadAttestations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(PayloadAttestation) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadAttestations[%d]", idx1) + } + } + } + { // Dynamic Field #12 'ParentExecutionRequests' + if canSeek { + enc.EncodeOffsetAt(offset12, uint32(enc.GetPosition()-dstlen)) + } + t := t.ParentExecutionRequests + if t == nil { + t = new(ExecutionRequests) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BeaconBlockBody from SSZ-encoded bytes using dynamic specifications. +func (t *BeaconBlockBody) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 396 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 396) + } + { // Field #0 'RandaoReveal' (static) + buf := buf[0:96] + t.RandaoReveal = sszutils.ExpandSlice(t.RandaoReveal, 96) + copy(t.RandaoReveal[:], buf) + } + { // Field #1 'Eth1Data' (static) + buf := buf[96:168] + if t.Eth1Data == nil { + t.Eth1Data = new(generic.Eth1Data) + } + if err = t.Eth1Data.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + } + { // Field #2 'Graffiti' (static) + buf := buf[168:200] + copy(t.Graffiti[:], buf) + } + // Field #3 'ProposerSlashings' (offset) + offset3 := int(binary.LittleEndian.Uint32(buf[200:204])) + if offset3 != 396 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset3, 396), "ProposerSlashings:o") + } + // Field #4 'AttesterSlashings' (offset) + offset4 := int(binary.LittleEndian.Uint32(buf[204:208])) + if offset4 < offset3 || offset4 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset4, offset3, buflen), "AttesterSlashings:o") + } + // Field #5 'Attestations' (offset) + offset5 := int(binary.LittleEndian.Uint32(buf[208:212])) + if offset5 < offset4 || offset5 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset5, offset4, buflen), "Attestations:o") + } + // Field #6 'Deposits' (offset) + offset6 := int(binary.LittleEndian.Uint32(buf[212:216])) + if offset6 < offset5 || offset6 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset6, offset5, buflen), "Deposits:o") + } + // Field #7 'VoluntaryExits' (offset) + offset7 := int(binary.LittleEndian.Uint32(buf[216:220])) + if offset7 < offset6 || offset7 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset7, offset6, buflen), "VoluntaryExits:o") + } + { // Field #8 'SyncAggregate' (static) + buf := buf[220:380] + if t.SyncAggregate == nil { + t.SyncAggregate = new(generic.SyncAggregate) + } + if err = t.SyncAggregate.UnmarshalSSZ(buf); err != nil { + return sszutils.ErrorWithPath(err, "SyncAggregate") + } + } + // Field #9 'BlsToExecutionChanges' (offset) + offset9 := int(binary.LittleEndian.Uint32(buf[380:384])) + if offset9 < offset7 || offset9 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset9, offset7, buflen), "BlsToExecutionChanges:o") + } + // Field #10 'SignedExecutionPayloadBid' (offset) + offset10 := int(binary.LittleEndian.Uint32(buf[384:388])) + if offset10 < offset9 || offset10 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset10, offset9, buflen), "SignedExecutionPayloadBid:o") + } + // Field #11 'PayloadAttestations' (offset) + offset11 := int(binary.LittleEndian.Uint32(buf[388:392])) + if offset11 < offset10 || offset11 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset11, offset10, buflen), "PayloadAttestations:o") + } + // Field #12 'ParentExecutionRequests' (offset) + offset12 := int(binary.LittleEndian.Uint32(buf[392:396])) + if offset12 < offset11 || offset12 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset12, offset11, buflen), "ParentExecutionRequests:o") + } + { // Field #3 'ProposerSlashings' (dynamic) + buf := buf[offset3:offset4] + val1 := t.ProposerSlashings + itemCount := len(buf) / 416 + if len(buf)%416 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 416), "ProposerSlashings") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "ProposerSlashings") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + for idx1 := range itemCount { + if val1[idx1] == nil { + val1[idx1] = new(generic.ProposerSlashing) + } + buf := buf[416*idx1 : 416*(idx1+1)] + if err = val1[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "ProposerSlashings[%d]", idx1) + } + } + t.ProposerSlashings = val1 + } + { // Field #4 'AttesterSlashings' (dynamic) + buf := buf[offset4:offset5] + val2 := t.AttesterSlashings + startOffset := int(0) + if len(buf) != 0 { + if len(buf) < 4 { + return sszutils.ErrorWithPath(sszutils.ErrListOffsetsEOFFn(len(buf), 4), "AttesterSlashings") + } + startOffset = int(binary.LittleEndian.Uint32(buf[0:4])) + } + itemCount := startOffset / 4 + if startOffset%4 != 0 || len(buf) < startOffset || (len(buf) != 0 && startOffset == 0) { + return sszutils.ErrorWithPath(sszutils.ErrInvalidListStartOffsetFn(startOffset, len(buf)), "AttesterSlashings") + } + if itemCount > 1 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1), "AttesterSlashings") + } + val2 = sszutils.ExpandSlice(val2, itemCount) + for idx1 := range itemCount { + var endOffset int + if idx1 < itemCount-1 { + endOffset = int(binary.LittleEndian.Uint32(buf[(idx1+1)*4 : (idx1+2)*4])) + } else { + endOffset = len(buf) + } + if endOffset < startOffset || endOffset > len(buf) { + return sszutils.ErrorWithPathf(sszutils.ErrElementOffsetOutOfRangeFn(endOffset, startOffset, len(buf)), "AttesterSlashings[%d]", idx1) + } + buf := buf[startOffset:endOffset] + startOffset = endOffset + val3 := val2[idx1] + if val3 == nil { + val3 = new(AttesterSlashing) + } + if err = val3.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "AttesterSlashings[%d]", idx1) + } + val2[idx1] = val3 + } + t.AttesterSlashings = val2 + } + { // Field #5 'Attestations' (dynamic) + buf := buf[offset5:offset6] + val4 := t.Attestations + startOffset := int(0) + if len(buf) != 0 { + if len(buf) < 4 { + return sszutils.ErrorWithPath(sszutils.ErrListOffsetsEOFFn(len(buf), 4), "Attestations") + } + startOffset = int(binary.LittleEndian.Uint32(buf[0:4])) + } + itemCount := startOffset / 4 + if startOffset%4 != 0 || len(buf) < startOffset || (len(buf) != 0 && startOffset == 0) { + return sszutils.ErrorWithPath(sszutils.ErrInvalidListStartOffsetFn(startOffset, len(buf)), "Attestations") + } + if itemCount > 8 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 8), "Attestations") + } + val4 = sszutils.ExpandSlice(val4, itemCount) + for idx1 := range itemCount { + var endOffset int + if idx1 < itemCount-1 { + endOffset = int(binary.LittleEndian.Uint32(buf[(idx1+1)*4 : (idx1+2)*4])) + } else { + endOffset = len(buf) + } + if endOffset < startOffset || endOffset > len(buf) { + return sszutils.ErrorWithPathf(sszutils.ErrElementOffsetOutOfRangeFn(endOffset, startOffset, len(buf)), "Attestations[%d]", idx1) + } + buf := buf[startOffset:endOffset] + startOffset = endOffset + val5 := val4[idx1] + if val5 == nil { + val5 = new(Attestation) + } + if err = val5.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Attestations[%d]", idx1) + } + val4[idx1] = val5 + } + t.Attestations = val4 + } + { // Field #6 'Deposits' (dynamic) + buf := buf[offset6:offset7] + val6 := t.Deposits + itemCount := len(buf) / 1240 + if len(buf)%1240 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 1240), "Deposits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "Deposits") + } + val6 = sszutils.ExpandSlice(val6, itemCount) + for idx1 := range itemCount { + if val6[idx1] == nil { + val6[idx1] = new(generic.Deposit) + } + buf := buf[1240*idx1 : 1240*(idx1+1)] + if err = val6[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + t.Deposits = val6 + } + { // Field #7 'VoluntaryExits' (dynamic) + buf := buf[offset7:offset9] + val7 := t.VoluntaryExits + itemCount := len(buf) / 112 + if len(buf)%112 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 112), "VoluntaryExits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "VoluntaryExits") + } + val7 = sszutils.ExpandSlice(val7, itemCount) + for idx1 := range itemCount { + if val7[idx1] == nil { + val7[idx1] = new(generic.SignedVoluntaryExit) + } + buf := buf[112*idx1 : 112*(idx1+1)] + if err = val7[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "VoluntaryExits[%d]", idx1) + } + } + t.VoluntaryExits = val7 + } + { // Field #9 'BlsToExecutionChanges' (dynamic) + buf := buf[offset9:offset10] + val8 := t.BlsToExecutionChanges + itemCount := len(buf) / 172 + if len(buf)%172 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 172), "BlsToExecutionChanges") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "BlsToExecutionChanges") + } + val8 = sszutils.ExpandSlice(val8, itemCount) + for idx1 := range itemCount { + if val8[idx1] == nil { + val8[idx1] = new(generic.SignedBLSToExecutionChange) + } + buf := buf[172*idx1 : 172*(idx1+1)] + if err = val8[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "BlsToExecutionChanges[%d]", idx1) + } + } + t.BlsToExecutionChanges = val8 + } + { // Field #10 'SignedExecutionPayloadBid' (dynamic) + buf := buf[offset10:offset11] + if t.SignedExecutionPayloadBid == nil { + t.SignedExecutionPayloadBid = new(SignedExecutionPayloadBid) + } + if err = t.SignedExecutionPayloadBid.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + } + { // Field #11 'PayloadAttestations' (dynamic) + buf := buf[offset11:offset12] + val9 := t.PayloadAttestations + itemCount := len(buf) / 202 + if len(buf)%202 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 202), "PayloadAttestations") + } + if itemCount > 4 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 4), "PayloadAttestations") + } + val9 = sszutils.ExpandSlice(val9, itemCount) + for idx1 := range itemCount { + if val9[idx1] == nil { + val9[idx1] = new(PayloadAttestation) + } + buf := buf[202*idx1 : 202*(idx1+1)] + if err = val9[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadAttestations[%d]", idx1) + } + } + t.PayloadAttestations = val9 + } + { // Field #12 'ParentExecutionRequests' (dynamic) + buf := buf[offset12:] + if t.ParentExecutionRequests == nil { + t.ParentExecutionRequests = new(ExecutionRequests) + } + if err = t.ParentExecutionRequests.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *BeaconBlockBody from the given SSZ decoder using dynamic specifications. +func (t *BeaconBlockBody) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + canSeek := dec.Seekable() + offsetSlices := [1][]uint32{ + sszutils.GetOffsetSlice(0), + } + defer func() { + sszutils.PutOffsetSlice(offsetSlices[0]) + }() + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(396) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(396)) + } + // Field #0 'RandaoReveal' (static) + t.RandaoReveal = sszutils.ExpandSlice(t.RandaoReveal, 96) + if _, err = dec.DecodeBytes(t.RandaoReveal[:96]); err != nil { + return err + } + // Field #1 'Eth1Data' (static) + if t.Eth1Data == nil { + t.Eth1Data = new(generic.Eth1Data) + } + if err = t.Eth1Data.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + // Field #2 'Graffiti' (static) + if _, err = dec.DecodeBytes(t.Graffiti[:32]); err != nil { + return err + } + // Field #3 'ProposerSlashings' (offset) + offset3, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "ProposerSlashings") + } + if offset3 != uint32(396) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset3, 396), "ProposerSlashings") + } + // Field #4 'AttesterSlashings' (offset) + offset4, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "AttesterSlashings") + } + if offset4 < offset3 || offset4 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset4, offset3, maxOffset), "AttesterSlashings") + } + // Field #5 'Attestations' (offset) + offset5, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Attestations") + } + if offset5 < offset4 || offset5 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset5, offset4, maxOffset), "Attestations") + } + // Field #6 'Deposits' (offset) + offset6, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Deposits") + } + if offset6 < offset5 || offset6 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset6, offset5, maxOffset), "Deposits") + } + // Field #7 'VoluntaryExits' (offset) + offset7, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "VoluntaryExits") + } + if offset7 < offset6 || offset7 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset7, offset6, maxOffset), "VoluntaryExits") + } + // Field #8 'SyncAggregate' (static) + if t.SyncAggregate == nil { + t.SyncAggregate = new(generic.SyncAggregate) + } + if err = t.SyncAggregate.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "SyncAggregate") + } + // Field #9 'BlsToExecutionChanges' (offset) + offset9, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "BlsToExecutionChanges") + } + if offset9 < offset7 || offset9 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset9, offset7, maxOffset), "BlsToExecutionChanges") + } + // Field #10 'SignedExecutionPayloadBid' (offset) + offset10, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + if offset10 < offset9 || offset10 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset10, offset9, maxOffset), "SignedExecutionPayloadBid") + } + // Field #11 'PayloadAttestations' (offset) + offset11, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "PayloadAttestations") + } + if offset11 < offset10 || offset11 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset11, offset10, maxOffset), "PayloadAttestations") + } + // Field #12 'ParentExecutionRequests' (offset) + offset12, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + if offset12 < offset11 || offset12 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset12, offset11, maxOffset), "ParentExecutionRequests") + } + { // Field #3 'ProposerSlashings' (dynamic) + if dec.GetPosition() != startPos0+int(offset3) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset3)), "ProposerSlashings") + } + dec.PushLimit(int(offset4 - offset3)) + val1 := t.ProposerSlashings + sszLen := dec.GetLength() + itemCount := sszLen / 416 + if sszLen%416 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 416), "ProposerSlashings") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "ProposerSlashings") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + startPos1 := dec.GetPosition() + for idx1 := range itemCount { + if val1[idx1] == nil { + val1[idx1] = new(generic.ProposerSlashing) + } + if err = val1[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "ProposerSlashings[%d]", idx1) + } + if dec.GetPosition() != startPos1+int(416*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos1+int(416*(idx1+1))), "ProposerSlashings[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "ProposerSlashings") + } + t.ProposerSlashings = val1 + } + { // Field #4 'AttesterSlashings' (dynamic) + if dec.GetPosition() != startPos0+int(offset4) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset4)), "AttesterSlashings") + } + dec.PushLimit(int(offset5 - offset4)) + val2 := t.AttesterSlashings + startOffset := uint32(0) + startPos2 := dec.GetPosition() + sszLen := uint32(dec.GetLength()) + if sszLen > 0 { + startOffset, err = dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "AttesterSlashings") + } + } + itemCount := int(startOffset / 4) + var offsets []uint32 + if canSeek { + dec.SkipBytes((itemCount - 1) * 4) + } else if itemCount > 1 { + offsetSlices[0] = sszutils.ExpandSlice(offsetSlices[0], itemCount-1) + offsets = offsetSlices[0] + for idx1 := range itemCount - 1 { + offset, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPathf(err, "AttesterSlashings[%d:o]", idx1) + } + offsets[idx1] = offset + } + } + if startOffset%4 != 0 || uint32(sszLen) < startOffset { + return sszutils.ErrorWithPath(sszutils.ErrInvalidListStartOffsetFn(startOffset, sszLen), "AttesterSlashings") + } + if itemCount > 1 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 1), "AttesterSlashings") + } + val2 = sszutils.ExpandSlice(val2, itemCount) + for idx1 := range itemCount { + var endOffset uint32 + if idx1 < itemCount-1 { + if canSeek { + endOffset = dec.DecodeOffsetAt(startPos2 + int((idx1+1)*4)) + } else { + endOffset = offsets[idx1] + } + } else { + endOffset = uint32(sszLen) + } + if endOffset < startOffset || endOffset > uint32(sszLen) { + return sszutils.ErrorWithPathf(sszutils.ErrElementOffsetOutOfRangeFn(endOffset, startOffset, sszLen), "AttesterSlashings[%d]", idx1) + } + itemSize := endOffset - startOffset + dec.PushLimit(int(itemSize)) + startOffset = endOffset + val3 := val2[idx1] + if val3 == nil { + val3 = new(AttesterSlashing) + } + if err = val3.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "AttesterSlashings[%d]", idx1) + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPathf(sszutils.ErrTrailingDataFn(diff), "AttesterSlashings[%d]", idx1) + } + val2[idx1] = val3 + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "AttesterSlashings") + } + t.AttesterSlashings = val2 + } + { // Field #5 'Attestations' (dynamic) + if dec.GetPosition() != startPos0+int(offset5) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset5)), "Attestations") + } + dec.PushLimit(int(offset6 - offset5)) + val4 := t.Attestations + startOffset := uint32(0) + startPos3 := dec.GetPosition() + sszLen := uint32(dec.GetLength()) + if sszLen > 0 { + startOffset, err = dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Attestations") + } + } + itemCount := int(startOffset / 4) + var offsets []uint32 + if canSeek { + dec.SkipBytes((itemCount - 1) * 4) + } else if itemCount > 1 { + offsetSlices[0] = sszutils.ExpandSlice(offsetSlices[0], itemCount-1) + offsets = offsetSlices[0] + for idx1 := range itemCount - 1 { + offset, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPathf(err, "Attestations[%d:o]", idx1) + } + offsets[idx1] = offset + } + } + if startOffset%4 != 0 || uint32(sszLen) < startOffset { + return sszutils.ErrorWithPath(sszutils.ErrInvalidListStartOffsetFn(startOffset, sszLen), "Attestations") + } + if itemCount > 8 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 8), "Attestations") + } + val4 = sszutils.ExpandSlice(val4, itemCount) + for idx1 := range itemCount { + var endOffset uint32 + if idx1 < itemCount-1 { + if canSeek { + endOffset = dec.DecodeOffsetAt(startPos3 + int((idx1+1)*4)) + } else { + endOffset = offsets[idx1] + } + } else { + endOffset = uint32(sszLen) + } + if endOffset < startOffset || endOffset > uint32(sszLen) { + return sszutils.ErrorWithPathf(sszutils.ErrElementOffsetOutOfRangeFn(endOffset, startOffset, sszLen), "Attestations[%d]", idx1) + } + itemSize := endOffset - startOffset + dec.PushLimit(int(itemSize)) + startOffset = endOffset + val5 := val4[idx1] + if val5 == nil { + val5 = new(Attestation) + } + if err = val5.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Attestations[%d]", idx1) + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPathf(sszutils.ErrTrailingDataFn(diff), "Attestations[%d]", idx1) + } + val4[idx1] = val5 + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Attestations") + } + t.Attestations = val4 + } + { // Field #6 'Deposits' (dynamic) + if dec.GetPosition() != startPos0+int(offset6) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset6)), "Deposits") + } + dec.PushLimit(int(offset7 - offset6)) + val6 := t.Deposits + sszLen := dec.GetLength() + itemCount := sszLen / 1240 + if sszLen%1240 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 1240), "Deposits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "Deposits") + } + val6 = sszutils.ExpandSlice(val6, itemCount) + startPos4 := dec.GetPosition() + for idx1 := range itemCount { + if val6[idx1] == nil { + val6[idx1] = new(generic.Deposit) + } + if err = val6[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + if dec.GetPosition() != startPos4+int(1240*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos4+int(1240*(idx1+1))), "Deposits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Deposits") + } + t.Deposits = val6 + } + { // Field #7 'VoluntaryExits' (dynamic) + if dec.GetPosition() != startPos0+int(offset7) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset7)), "VoluntaryExits") + } + dec.PushLimit(int(offset9 - offset7)) + val7 := t.VoluntaryExits + sszLen := dec.GetLength() + itemCount := sszLen / 112 + if sszLen%112 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 112), "VoluntaryExits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "VoluntaryExits") + } + val7 = sszutils.ExpandSlice(val7, itemCount) + startPos5 := dec.GetPosition() + for idx1 := range itemCount { + if val7[idx1] == nil { + val7[idx1] = new(generic.SignedVoluntaryExit) + } + if err = val7[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "VoluntaryExits[%d]", idx1) + } + if dec.GetPosition() != startPos5+int(112*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos5+int(112*(idx1+1))), "VoluntaryExits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "VoluntaryExits") + } + t.VoluntaryExits = val7 + } + { // Field #9 'BlsToExecutionChanges' (dynamic) + if dec.GetPosition() != startPos0+int(offset9) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset9)), "BlsToExecutionChanges") + } + dec.PushLimit(int(offset10 - offset9)) + val8 := t.BlsToExecutionChanges + sszLen := dec.GetLength() + itemCount := sszLen / 172 + if sszLen%172 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 172), "BlsToExecutionChanges") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "BlsToExecutionChanges") + } + val8 = sszutils.ExpandSlice(val8, itemCount) + startPos6 := dec.GetPosition() + for idx1 := range itemCount { + if val8[idx1] == nil { + val8[idx1] = new(generic.SignedBLSToExecutionChange) + } + if err = val8[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "BlsToExecutionChanges[%d]", idx1) + } + if dec.GetPosition() != startPos6+int(172*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos6+int(172*(idx1+1))), "BlsToExecutionChanges[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "BlsToExecutionChanges") + } + t.BlsToExecutionChanges = val8 + } + { // Field #10 'SignedExecutionPayloadBid' (dynamic) + if dec.GetPosition() != startPos0+int(offset10) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset10)), "SignedExecutionPayloadBid") + } + dec.PushLimit(int(offset11 - offset10)) + val9 := t.SignedExecutionPayloadBid + if val9 == nil { + val9 = new(SignedExecutionPayloadBid) + } + if err = val9.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "SignedExecutionPayloadBid") + } + t.SignedExecutionPayloadBid = val9 + } + { // Field #11 'PayloadAttestations' (dynamic) + if dec.GetPosition() != startPos0+int(offset11) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset11)), "PayloadAttestations") + } + dec.PushLimit(int(offset12 - offset11)) + val10 := t.PayloadAttestations + sszLen := dec.GetLength() + itemCount := sszLen / 202 + if sszLen%202 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 202), "PayloadAttestations") + } + if itemCount > 4 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 4), "PayloadAttestations") + } + val10 = sszutils.ExpandSlice(val10, itemCount) + startPos7 := dec.GetPosition() + for idx1 := range itemCount { + if val10[idx1] == nil { + val10[idx1] = new(PayloadAttestation) + } + if err = val10[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadAttestations[%d]", idx1) + } + if dec.GetPosition() != startPos7+int(202*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos7+int(202*(idx1+1))), "PayloadAttestations[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "PayloadAttestations") + } + t.PayloadAttestations = val10 + } + { // Field #12 'ParentExecutionRequests' (dynamic) + if dec.GetPosition() != startPos0+int(offset12) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset12)), "ParentExecutionRequests") + } + dec.PushLimit(int(maxOffset - offset12)) + val11 := t.ParentExecutionRequests + if val11 == nil { + val11 = new(ExecutionRequests) + } + if err = val11.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "ParentExecutionRequests") + } + t.ParentExecutionRequests = val11 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *BeaconBlockBody using dynamic specifications. +func (t *BeaconBlockBody) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(BeaconBlockBody) + } + // Field #0 'RandaoReveal' static (96 bytes) + // Field #1 'Eth1Data' static (72 bytes) + // Field #2 'Graffiti' static (32 bytes) + // Field #3 'ProposerSlashings' offset (4 bytes) + // Field #4 'AttesterSlashings' offset (4 bytes) + // Field #5 'Attestations' offset (4 bytes) + // Field #6 'Deposits' offset (4 bytes) + // Field #7 'VoluntaryExits' offset (4 bytes) + // Field #8 'SyncAggregate' static (160 bytes) + // Field #9 'BlsToExecutionChanges' offset (4 bytes) + // Field #10 'SignedExecutionPayloadBid' offset (4 bytes) + // Field #11 'PayloadAttestations' offset (4 bytes) + // Field #12 'ParentExecutionRequests' offset (4 bytes) + size += 396 + { // Dynamic field #3 'ProposerSlashings' + size += len(t.ProposerSlashings) * 416 + } + { // Dynamic field #4 'AttesterSlashings' + t := t.AttesterSlashings + vlen := len(t) + size += vlen * 4 // Offsets + for i1 := range vlen { + size += t[i1].SizeSSZDyn(ds) + } + } + { // Dynamic field #5 'Attestations' + t := t.Attestations + vlen := len(t) + size += vlen * 4 // Offsets + for i2 := range vlen { + size += t[i2].SizeSSZDyn(ds) + } + } + { // Dynamic field #6 'Deposits' + size += len(t.Deposits) * 1240 + } + { // Dynamic field #7 'VoluntaryExits' + size += len(t.VoluntaryExits) * 112 + } + { // Dynamic field #9 'BlsToExecutionChanges' + size += len(t.BlsToExecutionChanges) * 172 + } + { // Dynamic field #10 'SignedExecutionPayloadBid' + size += t.SignedExecutionPayloadBid.SizeSSZDyn(ds) + } + { // Dynamic field #11 'PayloadAttestations' + size += len(t.PayloadAttestations) * 202 + } + { // Dynamic field #12 'ParentExecutionRequests' + size += t.ParentExecutionRequests.SizeSSZDyn(ds) + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BeaconBlockBody using dynamic specifications. +func (t *BeaconBlockBody) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BeaconBlockBody using dynamic specifications and the given hash walker. +func (t *BeaconBlockBody) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(BeaconBlockBody) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'RandaoReveal' + vlen := len(t.RandaoReveal) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "RandaoReveal") + } + val := t.RandaoReveal[:] + if vlen < 96 { + val = sszutils.AppendZeroPadding(val, (96-vlen)*1) + } + hh.PutBytes(val[:96]) + } + { // Field #1 'Eth1Data' + t := t.Eth1Data + if t == nil { + t = new(generic.Eth1Data) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Eth1Data") + } + } + { // Field #2 'Graffiti' + hh.PutBytes(t.Graffiti[:32]) + } + { // Field #3 'ProposerSlashings' + t := t.ProposerSlashings + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "ProposerSlashings") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.ProposerSlashing) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "ProposerSlashings[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #4 'AttesterSlashings' + t := t.AttesterSlashings + vlen := uint64(len(t)) + if vlen > 1 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 1), "AttesterSlashings") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(AttesterSlashing) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "AttesterSlashings[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #5 'Attestations' + t := t.Attestations + vlen := uint64(len(t)) + if vlen > 8 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8), "Attestations") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(Attestation) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Attestations[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #6 'Deposits' + t := t.Deposits + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Deposits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.Deposit) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #7 'VoluntaryExits' + t := t.VoluntaryExits + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "VoluntaryExits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.SignedVoluntaryExit) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "VoluntaryExits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #8 'SyncAggregate' + t := t.SyncAggregate + if t == nil { + t = new(generic.SyncAggregate) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "SyncAggregate") + } + } + { // Field #9 'BlsToExecutionChanges' + t := t.BlsToExecutionChanges + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BlsToExecutionChanges") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(generic.SignedBLSToExecutionChange) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "BlsToExecutionChanges[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #10 'SignedExecutionPayloadBid' + t := t.SignedExecutionPayloadBid + if t == nil { + t = new(SignedExecutionPayloadBid) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "SignedExecutionPayloadBid") + } + } + { // Field #11 'PayloadAttestations' + t := t.PayloadAttestations + vlen := uint64(len(t)) + if vlen > 4 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4), "PayloadAttestations") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(PayloadAttestation) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "PayloadAttestations[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #12 'ParentExecutionRequests' + t := t.ParentExecutionRequests + if t == nil { + t = new(ExecutionRequests) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "ParentExecutionRequests") + } + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0xff, 0x1f}) + return nil +} + +// MarshalSSZTo marshals the *Builder to SSZ-encoded bytes, appending to the provided buffer. +func (t *Builder) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(Builder) + } + { // Static Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + dst = append(dst, t.Pubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + { // Static Field #1 'Version' + dst = append(dst, byte(t.Version)) + } + { // Static Field #2 'ExecutionAddress' + dst = append(dst, t.ExecutionAddress[:20]...) + } + { // Static Field #3 'Balance' + dst = binary.LittleEndian.AppendUint64(dst, t.Balance) + } + { // Static Field #4 'DepositEpoch' + dst = binary.LittleEndian.AppendUint64(dst, t.DepositEpoch) + } + { // Static Field #5 'WithdrawableEpoch' + dst = binary.LittleEndian.AppendUint64(dst, t.WithdrawableEpoch) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *Builder to SSZ-encoded bytes using dynamic specifications. +func (t *Builder) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *Builder to the given SSZ encoder using dynamic specifications. +func (t *Builder) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(Builder) + } + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + enc.EncodeBytes(t.Pubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + { // Field #1 'Version' + enc.EncodeUint8(byte(t.Version)) + } + { // Field #2 'ExecutionAddress' + enc.EncodeBytes(t.ExecutionAddress[:20]) + } + { // Field #3 'Balance' + enc.EncodeUint64(t.Balance) + } + { // Field #4 'DepositEpoch' + enc.EncodeUint64(t.DepositEpoch) + } + { // Field #5 'WithdrawableEpoch' + enc.EncodeUint64(t.WithdrawableEpoch) + } + return nil +} + +// UnmarshalSSZ unmarshals the *Builder from SSZ-encoded bytes. +func (t *Builder) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 93 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 93) + } + if buflen > 93 { + return sszutils.ErrTrailingDataFn(buflen - 93) + } + { // Field #0 'Pubkey' (static) + buf := buf[0:48] + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + copy(t.Pubkey[:], buf) + } + { // Field #1 'Version' (static) + buf := buf[48:49] + t.Version = buf[0] + } + { // Field #2 'ExecutionAddress' (static) + buf := buf[49:69] + copy(t.ExecutionAddress[:], buf) + } + { // Field #3 'Balance' (static) + buf := buf[69:77] + t.Balance = binary.LittleEndian.Uint64(buf) + } + { // Field #4 'DepositEpoch' (static) + buf := buf[77:85] + t.DepositEpoch = binary.LittleEndian.Uint64(buf) + } + { // Field #5 'WithdrawableEpoch' (static) + buf := buf[85:93] + t.WithdrawableEpoch = binary.LittleEndian.Uint64(buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *Builder from SSZ-encoded bytes using dynamic specifications. +func (t *Builder) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *Builder from the given SSZ decoder using dynamic specifications. +func (t *Builder) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(93) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(93)) + } + // Field #0 'Pubkey' (static) + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + if _, err = dec.DecodeBytes(t.Pubkey[:48]); err != nil { + return err + } + // Field #1 'Version' (static) + if val, err := dec.DecodeUint8(); err != nil { + return sszutils.ErrorWithPath(err, "Version") + } else { + t.Version = val + } + // Field #2 'ExecutionAddress' (static) + if _, err = dec.DecodeBytes(t.ExecutionAddress[:20]); err != nil { + return err + } + // Field #3 'Balance' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Balance") + } else { + t.Balance = val + } + // Field #4 'DepositEpoch' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "DepositEpoch") + } else { + t.DepositEpoch = val + } + // Field #5 'WithdrawableEpoch' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "WithdrawableEpoch") + } else { + t.WithdrawableEpoch = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *Builder. +func (t *Builder) SizeSSZ() (size int) { + return 93 +} + +// SizeSSZDyn returns the SSZ encoded size of the *Builder using dynamic specifications. +func (t *Builder) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *Builder. +func (t *Builder) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *Builder using the given hash walker. +func (t *Builder) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(Builder) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + val := t.Pubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + { // Field #1 'Version' + hh.PutUint8(t.Version) + } + { // Field #2 'ExecutionAddress' + hh.PutBytes(t.ExecutionAddress[:20]) + } + { // Field #3 'Balance' + hh.PutUint64(t.Balance) + } + { // Field #4 'DepositEpoch' + hh.PutUint64(t.DepositEpoch) + } + { // Field #5 'WithdrawableEpoch' + hh.PutUint64(t.WithdrawableEpoch) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *Builder using dynamic specifications. +func (t *Builder) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *Builder using dynamic specifications and the given hash walker. +func (t *Builder) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZTo marshals the *BuilderPendingWithdrawal to SSZ-encoded bytes, appending to the provided buffer. +func (t *BuilderPendingWithdrawal) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(BuilderPendingWithdrawal) + } + { // Static Field #0 'FeeRecipient' + dst = append(dst, t.FeeRecipient[:20]...) + } + { // Static Field #1 'Amount' + dst = binary.LittleEndian.AppendUint64(dst, t.Amount) + } + { // Static Field #2 'BuilderIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.BuilderIndex) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *BuilderPendingWithdrawal to SSZ-encoded bytes using dynamic specifications. +func (t *BuilderPendingWithdrawal) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *BuilderPendingWithdrawal to the given SSZ encoder using dynamic specifications. +func (t *BuilderPendingWithdrawal) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(BuilderPendingWithdrawal) + } + { // Field #0 'FeeRecipient' + enc.EncodeBytes(t.FeeRecipient[:20]) + } + { // Field #1 'Amount' + enc.EncodeUint64(t.Amount) + } + { // Field #2 'BuilderIndex' + enc.EncodeUint64(t.BuilderIndex) + } + return nil +} + +// UnmarshalSSZ unmarshals the *BuilderPendingWithdrawal from SSZ-encoded bytes. +func (t *BuilderPendingWithdrawal) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 36 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 36) + } + if buflen > 36 { + return sszutils.ErrTrailingDataFn(buflen - 36) + } + { // Field #0 'FeeRecipient' (static) + buf := buf[0:20] + copy(t.FeeRecipient[:], buf) + } + { // Field #1 'Amount' (static) + buf := buf[20:28] + t.Amount = binary.LittleEndian.Uint64(buf) + } + { // Field #2 'BuilderIndex' (static) + buf := buf[28:36] + t.BuilderIndex = binary.LittleEndian.Uint64(buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BuilderPendingWithdrawal from SSZ-encoded bytes using dynamic specifications. +func (t *BuilderPendingWithdrawal) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *BuilderPendingWithdrawal from the given SSZ decoder using dynamic specifications. +func (t *BuilderPendingWithdrawal) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(36) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(36)) + } + // Field #0 'FeeRecipient' (static) + if _, err = dec.DecodeBytes(t.FeeRecipient[:20]); err != nil { + return err + } + // Field #1 'Amount' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Amount") + } else { + t.Amount = val + } + // Field #2 'BuilderIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "BuilderIndex") + } else { + t.BuilderIndex = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *BuilderPendingWithdrawal. +func (t *BuilderPendingWithdrawal) SizeSSZ() (size int) { + return 36 +} + +// SizeSSZDyn returns the SSZ encoded size of the *BuilderPendingWithdrawal using dynamic specifications. +func (t *BuilderPendingWithdrawal) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *BuilderPendingWithdrawal. +func (t *BuilderPendingWithdrawal) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *BuilderPendingWithdrawal using the given hash walker. +func (t *BuilderPendingWithdrawal) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(BuilderPendingWithdrawal) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'FeeRecipient' + hh.PutBytes(t.FeeRecipient[:20]) + } + { // Field #1 'Amount' + hh.PutUint64(t.Amount) + } + { // Field #2 'BuilderIndex' + hh.PutUint64(t.BuilderIndex) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BuilderPendingWithdrawal using dynamic specifications. +func (t *BuilderPendingWithdrawal) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BuilderPendingWithdrawal using dynamic specifications and the given hash walker. +func (t *BuilderPendingWithdrawal) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZDyn marshals the *BuilderPendingPayment to SSZ-encoded bytes using dynamic specifications. +func (t *BuilderPendingPayment) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(BuilderPendingPayment) + } + { // Static Field #0 'Weight' + dst = binary.LittleEndian.AppendUint64(dst, t.Weight) + } + { // Static Field #1 'Withdrawal' + t := t.Withdrawal + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Withdrawal") + } + } + { // Static Field #2 'ProposerIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.ProposerIndex) + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *BuilderPendingPayment to the given SSZ encoder using dynamic specifications. +func (t *BuilderPendingPayment) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(BuilderPendingPayment) + } + { // Field #0 'Weight' + enc.EncodeUint64(t.Weight) + } + { // Field #1 'Withdrawal' + t := t.Withdrawal + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Withdrawal") + } + } + { // Field #2 'ProposerIndex' + enc.EncodeUint64(t.ProposerIndex) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BuilderPendingPayment from SSZ-encoded bytes using dynamic specifications. +func (t *BuilderPendingPayment) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 52 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 52) + } + if buflen > 52 { + return sszutils.ErrTrailingDataFn(buflen - 52) + } + { // Field #0 'Weight' (static) + buf := buf[0:8] + t.Weight = binary.LittleEndian.Uint64(buf) + } + { // Field #1 'Withdrawal' (static) + buf := buf[8:44] + if t.Withdrawal == nil { + t.Withdrawal = new(BuilderPendingWithdrawal) + } + if err = t.Withdrawal.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Withdrawal") + } + } + { // Field #2 'ProposerIndex' (static) + buf := buf[44:52] + t.ProposerIndex = binary.LittleEndian.Uint64(buf) + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *BuilderPendingPayment from the given SSZ decoder using dynamic specifications. +func (t *BuilderPendingPayment) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(52) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(52)) + } + // Field #0 'Weight' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Weight") + } else { + t.Weight = val + } + // Field #1 'Withdrawal' (static) + if t.Withdrawal == nil { + t.Withdrawal = new(BuilderPendingWithdrawal) + } + if err = t.Withdrawal.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Withdrawal") + } + // Field #2 'ProposerIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "ProposerIndex") + } else { + t.ProposerIndex = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *BuilderPendingPayment. +func (t *BuilderPendingPayment) SizeSSZ() (size int) { + return 52 +} + +// SizeSSZDyn returns the SSZ encoded size of the *BuilderPendingPayment using dynamic specifications. +func (t *BuilderPendingPayment) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BuilderPendingPayment using dynamic specifications. +func (t *BuilderPendingPayment) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BuilderPendingPayment using dynamic specifications and the given hash walker. +func (t *BuilderPendingPayment) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(BuilderPendingPayment) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Weight' + hh.PutUint64(t.Weight) + } + { // Field #1 'Withdrawal' + t := t.Withdrawal + if t == nil { + t = new(BuilderPendingWithdrawal) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Withdrawal") + } + } + { // Field #2 'ProposerIndex' + hh.PutUint64(t.ProposerIndex) + } + hh.Merkleize(idx) + return nil +} + +// MarshalSSZDyn marshals the *Attestation to SSZ-encoded bytes using dynamic specifications. +func (t *Attestation) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(Attestation) + } + dstlen := len(dst) + // Offset Field #0 'AggregationBits' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Data") + } + } + { // Static Field #2 'Signature' + dst = append(dst, t.Signature[:96]...) + } + { // Static Field #3 'CommitteeBits' + vlen := len(t.CommitteeBits) + if vlen > 8 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8), "CommitteeBits") + } + dst = append(dst, t.CommitteeBits[:vlen]...) + if vlen < 8 { + dst = sszutils.AppendZeroPadding(dst, (8-vlen)*1) + } + } + { // Dynamic Field #0 'AggregationBits' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.AggregationBits + vlen := len(t) + bval := []byte(t[:]) + if vlen == 0 { + bval = []byte{0x01} + } else if bval[vlen-1] == 0x00 { + return nil, sszutils.ErrorWithPath(sszutils.ErrBitlistNotTerminatedFn(), "AggregationBits") + } + if vlen > 0 { + bitCount := 8*(vlen-1) + bits.Len8(bval[vlen-1]) - 1 + if bitCount > 131072 { + return nil, sszutils.ErrorWithPath(sszutils.ErrBitlistLengthFn(bitCount, 131072), "AggregationBits") + } + } + dst = append(dst, bval...) + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *Attestation to the given SSZ encoder using dynamic specifications. +func (t *Attestation) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t go_bitfield.Bitlist) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for go_bitfield.Bitlist + ctx.sizeFn1 = func(ctx *encoderCtx, t go_bitfield.Bitlist) (size int) { + if len(t) == 0 { + size += 1 + } else { + size += len(t) + } + return size + } + if t == nil { + t = new(Attestation) + } + dstlen := enc.GetPosition() + dynoff := uint32(236) + // Offset #0 'AggregationBits' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.AggregationBits)) + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + enc.EncodeBytes(t.Signature[:96]) + } + { // Field #3 'CommitteeBits' + vlen := len(t.CommitteeBits) + if vlen > 8 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8), "CommitteeBits") + } + enc.EncodeBytes(t.CommitteeBits[:vlen]) + if vlen < 8 { + enc.EncodeZeroPadding((8 - vlen) * 1) + } + } + { // Dynamic Field #0 'AggregationBits' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.AggregationBits + vlen := len(t) + bval := []byte(t[:]) + if vlen == 0 { + bval = []byte{0x01} + } else if bval[vlen-1] == 0x00 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistNotTerminatedFn(), "AggregationBits") + } + if vlen > 0 { + bitCount := 8*(vlen-1) + bits.Len8(bval[vlen-1]) - 1 + if bitCount > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistLengthFn(bitCount, 131072), "AggregationBits") + } + } + enc.EncodeBytes(bval) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *Attestation from SSZ-encoded bytes using dynamic specifications. +func (t *Attestation) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 236 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 236) + } + // Field #0 'AggregationBits' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 236 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 236), "AggregationBits:o") + } + { // Field #1 'Data' (static) + buf := buf[4:132] + if t.Data == nil { + t.Data = new(generic.AttestationData) + } + if err = t.Data.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' (static) + buf := buf[132:228] + copy(t.Signature[:], buf) + } + { // Field #3 'CommitteeBits' (static) + buf := buf[228:236] + t.CommitteeBits = sszutils.ExpandSlice(t.CommitteeBits, 8) + copy(t.CommitteeBits[:], buf) + } + { // Field #0 'AggregationBits' (dynamic) + buf := buf[offset0:] + val1 := t.AggregationBits + blen := len(buf) + if blen == 0 || buf[blen-1] == 0x00 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistNotTerminatedFn(), "AggregationBits") + } + bitCount := 8*(blen-1) + int(bits.Len8(buf[blen-1])) - 1 + if bitCount > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistLengthFn(bitCount, 131072), "AggregationBits") + } + val1 = sszutils.ExpandSlice(val1, blen) + copy(val1[:], buf) + t.AggregationBits = val1 + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *Attestation from the given SSZ decoder using dynamic specifications. +func (t *Attestation) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(236) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(236)) + } + // Field #0 'AggregationBits' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "AggregationBits") + } + if offset0 != uint32(236) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 236), "AggregationBits") + } + // Field #1 'Data' (static) + if t.Data == nil { + t.Data = new(generic.AttestationData) + } + if err = t.Data.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + // Field #2 'Signature' (static) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + // Field #3 'CommitteeBits' (static) + t.CommitteeBits = sszutils.ExpandSlice(t.CommitteeBits, 8) + if _, err = dec.DecodeBytes(t.CommitteeBits[:8]); err != nil { + return err + } + { // Field #0 'AggregationBits' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "AggregationBits") + } + dec.PushLimit(int(maxOffset - offset0)) + val1 := t.AggregationBits + blen := dec.GetLength() + val1 = sszutils.ExpandSlice(val1, blen) + if _, err = dec.DecodeBytes(val1[:blen]); err != nil { + return sszutils.ErrorWithPath(err, "AggregationBits") + } + if blen == 0 || val1[blen-1] == 0x00 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistNotTerminatedFn(), "AggregationBits") + } + bitCount := 8*(blen-1) + int(bits.Len8(val1[blen-1])) - 1 + if bitCount > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistLengthFn(bitCount, 131072), "AggregationBits") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "AggregationBits") + } + t.AggregationBits = val1 + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *Attestation. +func (t *Attestation) SizeSSZ() (size int) { + if t == nil { + t = new(Attestation) + } + // Field #0 'AggregationBits' offset (4 bytes) + // Field #1 'Data' static (128 bytes) + // Field #2 'Signature' static (96 bytes) + // Field #3 'CommitteeBits' static (8 bytes) + size += 236 + { // Dynamic field #0 'AggregationBits' + if len(t.AggregationBits) == 0 { + size += 1 + } else { + size += len(t.AggregationBits) + } + } + return size +} + +// SizeSSZDyn returns the SSZ encoded size of the *Attestation using dynamic specifications. +func (t *Attestation) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *Attestation using dynamic specifications. +func (t *Attestation) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *Attestation using dynamic specifications and the given hash walker. +func (t *Attestation) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(Attestation) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'AggregationBits' + t := t.AggregationBits + if l := len(t); l > 0 && t[l-1] == 0x00 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistNotTerminatedFn(), "AggregationBits") + } + idx := hh.StartTree(sszutils.TreeTypeNone) + bitlist, size := hasher.ParseProgressiveBitlistWithHasher(hh, t[:]) + if size > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrBitlistLengthFn(size, 131072), "AggregationBits") + } + hh.AppendBytes32(bitlist) + hh.MerkleizeProgressiveWithMixin(idx, size) + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + hh.PutBytes(t.Signature[:96]) + } + { // Field #3 'CommitteeBits' + vlen := len(t.CommitteeBits) + if vlen > 8 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 8), "CommitteeBits") + } + val := t.CommitteeBits[:] + if vlen < 8 { + val = sszutils.AppendZeroPadding(val, (8-vlen)*1) + } + hh.PutBytes(val[:8]) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0x0f}) + return nil +} + +// MarshalSSZTo marshals the *ExecutionPayloadBid to SSZ-encoded bytes, appending to the provided buffer. +func (t *ExecutionPayloadBid) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(ExecutionPayloadBid) + } + dstlen := len(dst) + { // Static Field #0 'ParentBlockHash' + dst = append(dst, t.ParentBlockHash[:32]...) + } + { // Static Field #1 'ParentBlockRoot' + dst = append(dst, t.ParentBlockRoot[:32]...) + } + { // Static Field #2 'BlockHash' + dst = append(dst, t.BlockHash[:32]...) + } + { // Static Field #3 'PrevRandao' + dst = append(dst, t.PrevRandao[:32]...) + } + { // Static Field #4 'FeeRecipient' + dst = append(dst, t.FeeRecipient[:20]...) + } + { // Static Field #5 'GasLimit' + dst = binary.LittleEndian.AppendUint64(dst, t.GasLimit) + } + { // Static Field #6 'BuilderIndex' + dst = binary.LittleEndian.AppendUint64(dst, t.BuilderIndex) + } + { // Static Field #7 'Slot' + dst = binary.LittleEndian.AppendUint64(dst, t.Slot) + } + { // Static Field #8 'Value' + dst = binary.LittleEndian.AppendUint64(dst, t.Value) + } + { // Static Field #9 'ExecutionPayment' + dst = binary.LittleEndian.AppendUint64(dst, t.ExecutionPayment) + } + // Offset Field #10 'BlobKzgCommitments' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #11 'ExecutionRequestsRoot' + dst = append(dst, t.ExecutionRequestsRoot[:32]...) + } + { // Dynamic Field #10 'BlobKzgCommitments' + binary.LittleEndian.PutUint32(dst[dstlen+188:], uint32(len(dst)-dstlen)) + t := t.BlobKzgCommitments + vlen := len(t) + if vlen > 4096 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4096), "BlobKzgCommitments") + } + dst = sszutils.MarshalFixedBytesSlice(dst, t[:vlen]) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *ExecutionPayloadBid to SSZ-encoded bytes using dynamic specifications. +func (t *ExecutionPayloadBid) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *ExecutionPayloadBid to the given SSZ encoder using dynamic specifications. +func (t *ExecutionPayloadBid) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t [][48]byte) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for [][48]byte + ctx.sizeFn1 = func(ctx *encoderCtx, t [][48]byte) (size int) { + size += len(t) * 48 + return size + } + if t == nil { + t = new(ExecutionPayloadBid) + } + dstlen := enc.GetPosition() + dynoff := uint32(224) + { // Field #0 'ParentBlockHash' + enc.EncodeBytes(t.ParentBlockHash[:32]) + } + { // Field #1 'ParentBlockRoot' + enc.EncodeBytes(t.ParentBlockRoot[:32]) + } + { // Field #2 'BlockHash' + enc.EncodeBytes(t.BlockHash[:32]) + } + { // Field #3 'PrevRandao' + enc.EncodeBytes(t.PrevRandao[:32]) + } + { // Field #4 'FeeRecipient' + enc.EncodeBytes(t.FeeRecipient[:20]) + } + { // Field #5 'GasLimit' + enc.EncodeUint64(t.GasLimit) + } + { // Field #6 'BuilderIndex' + enc.EncodeUint64(t.BuilderIndex) + } + { // Field #7 'Slot' + enc.EncodeUint64(t.Slot) + } + { // Field #8 'Value' + enc.EncodeUint64(t.Value) + } + { // Field #9 'ExecutionPayment' + enc.EncodeUint64(t.ExecutionPayment) + } + // Offset #10 'BlobKzgCommitments' + offset10 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.BlobKzgCommitments)) + } + { // Field #11 'ExecutionRequestsRoot' + enc.EncodeBytes(t.ExecutionRequestsRoot[:32]) + } + { // Dynamic Field #10 'BlobKzgCommitments' + if canSeek { + enc.EncodeOffsetAt(offset10, uint32(enc.GetPosition()-dstlen)) + } + t := t.BlobKzgCommitments + vlen := len(t) + if vlen > 4096 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4096), "BlobKzgCommitments") + } + for idx1 := range vlen { + enc.EncodeBytes(t[idx1][:48]) + } + } + return nil +} + +// UnmarshalSSZ unmarshals the *ExecutionPayloadBid from SSZ-encoded bytes. +func (t *ExecutionPayloadBid) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 224 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 224) + } + { // Field #0 'ParentBlockHash' (static) + buf := buf[0:32] + copy(t.ParentBlockHash[:], buf) + } + { // Field #1 'ParentBlockRoot' (static) + buf := buf[32:64] + copy(t.ParentBlockRoot[:], buf) + } + { // Field #2 'BlockHash' (static) + buf := buf[64:96] + copy(t.BlockHash[:], buf) + } + { // Field #3 'PrevRandao' (static) + buf := buf[96:128] + copy(t.PrevRandao[:], buf) + } + { // Field #4 'FeeRecipient' (static) + buf := buf[128:148] + copy(t.FeeRecipient[:], buf) + } + { // Field #5 'GasLimit' (static) + buf := buf[148:156] + t.GasLimit = binary.LittleEndian.Uint64(buf) + } + { // Field #6 'BuilderIndex' (static) + buf := buf[156:164] + t.BuilderIndex = binary.LittleEndian.Uint64(buf) + } + { // Field #7 'Slot' (static) + buf := buf[164:172] + t.Slot = binary.LittleEndian.Uint64(buf) + } + { // Field #8 'Value' (static) + buf := buf[172:180] + t.Value = binary.LittleEndian.Uint64(buf) + } + { // Field #9 'ExecutionPayment' (static) + buf := buf[180:188] + t.ExecutionPayment = binary.LittleEndian.Uint64(buf) + } + // Field #10 'BlobKzgCommitments' (offset) + offset10 := int(binary.LittleEndian.Uint32(buf[188:192])) + if offset10 != 224 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset10, 224), "BlobKzgCommitments:o") + } + { // Field #11 'ExecutionRequestsRoot' (static) + buf := buf[192:224] + copy(t.ExecutionRequestsRoot[:], buf) + } + { // Field #10 'BlobKzgCommitments' (dynamic) + buf := buf[offset10:] + val1 := t.BlobKzgCommitments + itemCount := len(buf) / 48 + if len(buf)%48 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 48), "BlobKzgCommitments") + } + if itemCount > 4096 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 4096), "BlobKzgCommitments") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + sszutils.UnmarshalFixedBytesSlice(val1[:itemCount], buf) + t.BlobKzgCommitments = val1 + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *ExecutionPayloadBid from SSZ-encoded bytes using dynamic specifications. +func (t *ExecutionPayloadBid) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *ExecutionPayloadBid from the given SSZ decoder using dynamic specifications. +func (t *ExecutionPayloadBid) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(224) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(224)) + } + // Field #0 'ParentBlockHash' (static) + if _, err = dec.DecodeBytes(t.ParentBlockHash[:32]); err != nil { + return err + } + // Field #1 'ParentBlockRoot' (static) + if _, err = dec.DecodeBytes(t.ParentBlockRoot[:32]); err != nil { + return err + } + // Field #2 'BlockHash' (static) + if _, err = dec.DecodeBytes(t.BlockHash[:32]); err != nil { + return err + } + // Field #3 'PrevRandao' (static) + if _, err = dec.DecodeBytes(t.PrevRandao[:32]); err != nil { + return err + } + // Field #4 'FeeRecipient' (static) + if _, err = dec.DecodeBytes(t.FeeRecipient[:20]); err != nil { + return err + } + // Field #5 'GasLimit' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "GasLimit") + } else { + t.GasLimit = val + } + // Field #6 'BuilderIndex' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "BuilderIndex") + } else { + t.BuilderIndex = val + } + // Field #7 'Slot' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Slot") + } else { + t.Slot = val + } + // Field #8 'Value' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Value") + } else { + t.Value = val + } + // Field #9 'ExecutionPayment' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "ExecutionPayment") + } else { + t.ExecutionPayment = val + } + // Field #10 'BlobKzgCommitments' (offset) + offset10, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "BlobKzgCommitments") + } + if offset10 != uint32(224) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset10, 224), "BlobKzgCommitments") + } + // Field #11 'ExecutionRequestsRoot' (static) + if _, err = dec.DecodeBytes(t.ExecutionRequestsRoot[:32]); err != nil { + return err + } + { // Field #10 'BlobKzgCommitments' (dynamic) + if dec.GetPosition() != startPos0+int(offset10) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset10)), "BlobKzgCommitments") + } + dec.PushLimit(int(maxOffset - offset10)) + val1 := t.BlobKzgCommitments + sszLen := dec.GetLength() + itemCount := sszLen / 48 + if sszLen%48 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 48), "BlobKzgCommitments") + } + if itemCount > 4096 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 4096), "BlobKzgCommitments") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + startPos1 := dec.GetPosition() + for idx1 := range itemCount { + if _, err = dec.DecodeBytes(val1[idx1][:48]); err != nil { + return err + } + if dec.GetPosition() != startPos1+int(48*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos1+int(48*(idx1+1))), "BlobKzgCommitments[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "BlobKzgCommitments") + } + t.BlobKzgCommitments = val1 + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *ExecutionPayloadBid. +func (t *ExecutionPayloadBid) SizeSSZ() (size int) { + if t == nil { + t = new(ExecutionPayloadBid) + } + // Field #0 'ParentBlockHash' static (32 bytes) + // Field #1 'ParentBlockRoot' static (32 bytes) + // Field #2 'BlockHash' static (32 bytes) + // Field #3 'PrevRandao' static (32 bytes) + // Field #4 'FeeRecipient' static (20 bytes) + // Field #5 'GasLimit' static (8 bytes) + // Field #6 'BuilderIndex' static (8 bytes) + // Field #7 'Slot' static (8 bytes) + // Field #8 'Value' static (8 bytes) + // Field #9 'ExecutionPayment' static (8 bytes) + // Field #10 'BlobKzgCommitments' offset (4 bytes) + // Field #11 'ExecutionRequestsRoot' static (32 bytes) + size += 224 + { // Dynamic field #10 'BlobKzgCommitments' + size += len(t.BlobKzgCommitments) * 48 + } + return size +} + +// SizeSSZDyn returns the SSZ encoded size of the *ExecutionPayloadBid using dynamic specifications. +func (t *ExecutionPayloadBid) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *ExecutionPayloadBid. +func (t *ExecutionPayloadBid) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *ExecutionPayloadBid using the given hash walker. +func (t *ExecutionPayloadBid) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(ExecutionPayloadBid) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'ParentBlockHash' + hh.PutBytes(t.ParentBlockHash[:32]) + } + { // Field #1 'ParentBlockRoot' + hh.PutBytes(t.ParentBlockRoot[:32]) + } + { // Field #2 'BlockHash' + hh.PutBytes(t.BlockHash[:32]) + } + { // Field #3 'PrevRandao' + hh.PutBytes(t.PrevRandao[:32]) + } + { // Field #4 'FeeRecipient' + hh.PutBytes(t.FeeRecipient[:20]) + } + { // Field #5 'GasLimit' + hh.PutUint64(t.GasLimit) + } + { // Field #6 'BuilderIndex' + hh.PutUint64(t.BuilderIndex) + } + { // Field #7 'Slot' + hh.PutUint64(t.Slot) + } + { // Field #8 'Value' + hh.PutUint64(t.Value) + } + { // Field #9 'ExecutionPayment' + hh.PutUint64(t.ExecutionPayment) + } + { // Field #10 'BlobKzgCommitments' + t := t.BlobKzgCommitments + vlen := uint64(len(t)) + if vlen > 4096 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 4096), "BlobKzgCommitments") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + hh.PutBytes(t[idx1][:48]) + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #11 'ExecutionRequestsRoot' + hh.PutBytes(t.ExecutionRequestsRoot[:32]) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0xff, 0x0f}) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *ExecutionPayloadBid using dynamic specifications. +func (t *ExecutionPayloadBid) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *ExecutionPayloadBid using dynamic specifications and the given hash walker. +func (t *ExecutionPayloadBid) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZDyn marshals the *SignedExecutionPayloadBid to SSZ-encoded bytes using dynamic specifications. +func (t *SignedExecutionPayloadBid) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(SignedExecutionPayloadBid) + } + dstlen := len(dst) + // Offset Field #0 'Message' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #1 'Signature' + dst = append(dst, t.Signature[:96]...) + } + { // Dynamic Field #0 'Message' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.Message + if t == nil { + t = new(ExecutionPayloadBid) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Message") + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *SignedExecutionPayloadBid to the given SSZ encoder using dynamic specifications. +func (t *SignedExecutionPayloadBid) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t *ExecutionPayloadBid) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for *ExecutionPayloadBid + ctx.sizeFn1 = func(ctx *encoderCtx, t *ExecutionPayloadBid) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + if t == nil { + t = new(SignedExecutionPayloadBid) + } + dstlen := enc.GetPosition() + dynoff := uint32(100) + // Offset #0 'Message' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Message)) + } + { // Field #1 'Signature' + enc.EncodeBytes(t.Signature[:96]) + } + { // Dynamic Field #0 'Message' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.Message + if t == nil { + t = new(ExecutionPayloadBid) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Message") + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *SignedExecutionPayloadBid from SSZ-encoded bytes using dynamic specifications. +func (t *SignedExecutionPayloadBid) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 100 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 100) + } + // Field #0 'Message' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 100 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 100), "Message:o") + } + { // Field #1 'Signature' (static) + buf := buf[4:100] + copy(t.Signature[:], buf) + } + { // Field #0 'Message' (dynamic) + buf := buf[offset0:] + if t.Message == nil { + t.Message = new(ExecutionPayloadBid) + } + if err = t.Message.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Message") + } + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *SignedExecutionPayloadBid from the given SSZ decoder using dynamic specifications. +func (t *SignedExecutionPayloadBid) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(100) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(100)) + } + // Field #0 'Message' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Message") + } + if offset0 != uint32(100) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 100), "Message") + } + // Field #1 'Signature' (static) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + { // Field #0 'Message' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "Message") + } + dec.PushLimit(int(maxOffset - offset0)) + val1 := t.Message + if val1 == nil { + val1 = new(ExecutionPayloadBid) + } + if err = val1.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Message") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Message") + } + t.Message = val1 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *SignedExecutionPayloadBid using dynamic specifications. +func (t *SignedExecutionPayloadBid) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(SignedExecutionPayloadBid) + } + // Field #0 'Message' offset (4 bytes) + // Field #1 'Signature' static (96 bytes) + size += 100 + { // Dynamic field #0 'Message' + size += t.Message.SizeSSZDyn(ds) + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *SignedExecutionPayloadBid using dynamic specifications. +func (t *SignedExecutionPayloadBid) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *SignedExecutionPayloadBid using dynamic specifications and the given hash walker. +func (t *SignedExecutionPayloadBid) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(SignedExecutionPayloadBid) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Message' + t := t.Message + if t == nil { + t = new(ExecutionPayloadBid) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Message") + } + } + { // Field #1 'Signature' + hh.PutBytes(t.Signature[:96]) + } + hh.Merkleize(idx) + return nil +} + +// MarshalSSZTo marshals the *PayloadAttestationData to SSZ-encoded bytes, appending to the provided buffer. +func (t *PayloadAttestationData) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(PayloadAttestationData) + } + { // Static Field #0 'BeaconBlockRoot' + dst = append(dst, t.BeaconBlockRoot[:32]...) + } + { // Static Field #1 'Slot' + dst = binary.LittleEndian.AppendUint64(dst, t.Slot) + } + { // Static Field #2 'PayloadPresent' + dst = sszutils.MarshalBool(dst, t.PayloadPresent) + } + { // Static Field #3 'BlobDataAvailable' + dst = sszutils.MarshalBool(dst, t.BlobDataAvailable) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *PayloadAttestationData to SSZ-encoded bytes using dynamic specifications. +func (t *PayloadAttestationData) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *PayloadAttestationData to the given SSZ encoder using dynamic specifications. +func (t *PayloadAttestationData) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(PayloadAttestationData) + } + { // Field #0 'BeaconBlockRoot' + enc.EncodeBytes(t.BeaconBlockRoot[:32]) + } + { // Field #1 'Slot' + enc.EncodeUint64(t.Slot) + } + { // Field #2 'PayloadPresent' + enc.EncodeBool(t.PayloadPresent) + } + { // Field #3 'BlobDataAvailable' + enc.EncodeBool(t.BlobDataAvailable) + } + return nil +} + +// UnmarshalSSZ unmarshals the *PayloadAttestationData from SSZ-encoded bytes. +func (t *PayloadAttestationData) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 42 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 42) + } + if buflen > 42 { + return sszutils.ErrTrailingDataFn(buflen - 42) + } + { // Field #0 'BeaconBlockRoot' (static) + buf := buf[0:32] + copy(t.BeaconBlockRoot[:], buf) + } + { // Field #1 'Slot' (static) + buf := buf[32:40] + t.Slot = binary.LittleEndian.Uint64(buf) + } + { // Field #2 'PayloadPresent' (static) + buf := buf[40:41] + if buf[0] != 1 && buf[0] != 0 { + return sszutils.ErrInvalidBoolValueFn() + } + t.PayloadPresent = buf[0] == 1 + } + { // Field #3 'BlobDataAvailable' (static) + buf := buf[41:42] + if buf[0] != 1 && buf[0] != 0 { + return sszutils.ErrInvalidBoolValueFn() + } + t.BlobDataAvailable = buf[0] == 1 + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *PayloadAttestationData from SSZ-encoded bytes using dynamic specifications. +func (t *PayloadAttestationData) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *PayloadAttestationData from the given SSZ decoder using dynamic specifications. +func (t *PayloadAttestationData) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(42) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(42)) + } + // Field #0 'BeaconBlockRoot' (static) + if _, err = dec.DecodeBytes(t.BeaconBlockRoot[:32]); err != nil { + return err + } + // Field #1 'Slot' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Slot") + } else { + t.Slot = val + } + // Field #2 'PayloadPresent' (static) + if val, err := dec.DecodeBool(); err != nil { + return sszutils.ErrorWithPath(err, "PayloadPresent") + } else { + t.PayloadPresent = val + } + // Field #3 'BlobDataAvailable' (static) + if val, err := dec.DecodeBool(); err != nil { + return sszutils.ErrorWithPath(err, "BlobDataAvailable") + } else { + t.BlobDataAvailable = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *PayloadAttestationData. +func (t *PayloadAttestationData) SizeSSZ() (size int) { + return 42 +} + +// SizeSSZDyn returns the SSZ encoded size of the *PayloadAttestationData using dynamic specifications. +func (t *PayloadAttestationData) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *PayloadAttestationData. +func (t *PayloadAttestationData) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *PayloadAttestationData using the given hash walker. +func (t *PayloadAttestationData) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(PayloadAttestationData) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'BeaconBlockRoot' + hh.PutBytes(t.BeaconBlockRoot[:32]) + } + { // Field #1 'Slot' + hh.PutUint64(t.Slot) + } + { // Field #2 'PayloadPresent' + hh.PutBool(t.PayloadPresent) + } + { // Field #3 'BlobDataAvailable' + hh.PutBool(t.BlobDataAvailable) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *PayloadAttestationData using dynamic specifications. +func (t *PayloadAttestationData) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *PayloadAttestationData using dynamic specifications and the given hash walker. +func (t *PayloadAttestationData) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZDyn marshals the *PayloadAttestation to SSZ-encoded bytes using dynamic specifications. +func (t *PayloadAttestation) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(PayloadAttestation) + } + { // Static Field #0 'AggregationBits' + vlen := len(t.AggregationBits) + if vlen > 64 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "AggregationBits") + } + dst = append(dst, t.AggregationBits[:vlen]...) + if vlen < 64 { + dst = sszutils.AppendZeroPadding(dst, (64-vlen)*1) + } + } + { // Static Field #1 'Data' + t := t.Data + if t == nil { + t = new(PayloadAttestationData) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Data") + } + } + { // Static Field #2 'Signature' + dst = append(dst, t.Signature[:96]...) + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *PayloadAttestation to the given SSZ encoder using dynamic specifications. +func (t *PayloadAttestation) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(PayloadAttestation) + } + { // Field #0 'AggregationBits' + vlen := len(t.AggregationBits) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "AggregationBits") + } + enc.EncodeBytes(t.AggregationBits[:vlen]) + if vlen < 64 { + enc.EncodeZeroPadding((64 - vlen) * 1) + } + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(PayloadAttestationData) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + enc.EncodeBytes(t.Signature[:96]) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *PayloadAttestation from SSZ-encoded bytes using dynamic specifications. +func (t *PayloadAttestation) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 202 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 202) + } + if buflen > 202 { + return sszutils.ErrTrailingDataFn(buflen - 202) + } + { // Field #0 'AggregationBits' (static) + buf := buf[0:64] + t.AggregationBits = sszutils.ExpandSlice(t.AggregationBits, 64) + copy(t.AggregationBits[:], buf) + } + { // Field #1 'Data' (static) + buf := buf[64:106] + if t.Data == nil { + t.Data = new(PayloadAttestationData) + } + if err = t.Data.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' (static) + buf := buf[106:202] + copy(t.Signature[:], buf) + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *PayloadAttestation from the given SSZ decoder using dynamic specifications. +func (t *PayloadAttestation) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(202) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(202)) + } + // Field #0 'AggregationBits' (static) + t.AggregationBits = sszutils.ExpandSlice(t.AggregationBits, 64) + if _, err = dec.DecodeBytes(t.AggregationBits[:64]); err != nil { + return err + } + // Field #1 'Data' (static) + if t.Data == nil { + t.Data = new(PayloadAttestationData) + } + if err = t.Data.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + // Field #2 'Signature' (static) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *PayloadAttestation. +func (t *PayloadAttestation) SizeSSZ() (size int) { + return 202 +} + +// SizeSSZDyn returns the SSZ encoded size of the *PayloadAttestation using dynamic specifications. +func (t *PayloadAttestation) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *PayloadAttestation using dynamic specifications. +func (t *PayloadAttestation) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *PayloadAttestation using dynamic specifications and the given hash walker. +func (t *PayloadAttestation) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(PayloadAttestation) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'AggregationBits' + vlen := len(t.AggregationBits) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 64), "AggregationBits") + } + val := t.AggregationBits[:] + if vlen < 64 { + val = sszutils.AppendZeroPadding(val, (64-vlen)*1) + } + hh.PutBytes(val[:64]) + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(PayloadAttestationData) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + hh.PutBytes(t.Signature[:96]) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0x07}) + return nil +} + +// MarshalSSZDyn marshals the *ExecutionRequests to SSZ-encoded bytes using dynamic specifications. +func (t *ExecutionRequests) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + zeroBytes := sszutils.ZeroBytes() + if t == nil { + t = new(ExecutionRequests) + } + dstlen := len(dst) + // Offset Field #0 'Deposits' + // Offset Field #1 'Withdrawals' + // Offset Field #2 'Consolidations' + // Offset Field #3 'BuilderDeposits' + // Offset Field #4 'BuilderExits' + dst = append(dst, zeroBytes[:20]...) + { // Dynamic Field #0 'Deposits' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.Deposits + vlen := len(t) + if vlen > 8192 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8192), "Deposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(DepositRequest) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + } + { // Dynamic Field #1 'Withdrawals' + binary.LittleEndian.PutUint32(dst[dstlen+4:], uint32(len(dst)-dstlen)) + t := t.Withdrawals + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Withdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(WithdrawalRequest) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Withdrawals[%d]", idx1) + } + } + } + { // Dynamic Field #2 'Consolidations' + binary.LittleEndian.PutUint32(dst[dstlen+8:], uint32(len(dst)-dstlen)) + t := t.Consolidations + vlen := len(t) + if vlen > 2 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2), "Consolidations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(ConsolidationRequest) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "Consolidations[%d]", idx1) + } + } + } + { // Dynamic Field #3 'BuilderDeposits' + binary.LittleEndian.PutUint32(dst[dstlen+12:], uint32(len(dst)-dstlen)) + t := t.BuilderDeposits + vlen := len(t) + if vlen > 64 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 64), "BuilderDeposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderDepositRequest) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "BuilderDeposits[%d]", idx1) + } + } + } + { // Dynamic Field #4 'BuilderExits' + binary.LittleEndian.PutUint32(dst[dstlen+16:], uint32(len(dst)-dstlen)) + t := t.BuilderExits + vlen := len(t) + if vlen > 16 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BuilderExits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderExitRequest) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPathf(err, "BuilderExits[%d]", idx1) + } + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *ExecutionRequests to the given SSZ encoder using dynamic specifications. +func (t *ExecutionRequests) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t []*DepositRequest) (size int) + sizeFn2 func(ctx *encoderCtx, t []*WithdrawalRequest) (size int) + sizeFn3 func(ctx *encoderCtx, t []*ConsolidationRequest) (size int) + sizeFn4 func(ctx *encoderCtx, t []*BuilderDepositRequest) (size int) + sizeFn5 func(ctx *encoderCtx, t []*BuilderExitRequest) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for []*DepositRequest + ctx.sizeFn1 = func(ctx *encoderCtx, t []*DepositRequest) (size int) { + size += len(t) * 192 + return size + } + // size for []*WithdrawalRequest + ctx.sizeFn2 = func(ctx *encoderCtx, t []*WithdrawalRequest) (size int) { + size += len(t) * 76 + return size + } + // size for []*ConsolidationRequest + ctx.sizeFn3 = func(ctx *encoderCtx, t []*ConsolidationRequest) (size int) { + size += len(t) * 116 + return size + } + // size for []*BuilderDepositRequest + ctx.sizeFn4 = func(ctx *encoderCtx, t []*BuilderDepositRequest) (size int) { + size += len(t) * 184 + return size + } + // size for []*BuilderExitRequest + ctx.sizeFn5 = func(ctx *encoderCtx, t []*BuilderExitRequest) (size int) { + size += len(t) * 68 + return size + } + if t == nil { + t = new(ExecutionRequests) + } + dstlen := enc.GetPosition() + dynoff := uint32(20) + // Offset #0 'Deposits' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Deposits)) + } + // Offset #1 'Withdrawals' + offset1 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn2(ctx, t.Withdrawals)) + } + // Offset #2 'Consolidations' + offset2 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn3(ctx, t.Consolidations)) + } + // Offset #3 'BuilderDeposits' + offset3 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn4(ctx, t.BuilderDeposits)) + } + // Offset #4 'BuilderExits' + offset4 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn5(ctx, t.BuilderExits)) + } + { // Dynamic Field #0 'Deposits' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.Deposits + vlen := len(t) + if vlen > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8192), "Deposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(DepositRequest) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + } + { // Dynamic Field #1 'Withdrawals' + if canSeek { + enc.EncodeOffsetAt(offset1, uint32(enc.GetPosition()-dstlen)) + } + t := t.Withdrawals + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Withdrawals") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(WithdrawalRequest) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Withdrawals[%d]", idx1) + } + } + } + { // Dynamic Field #2 'Consolidations' + if canSeek { + enc.EncodeOffsetAt(offset2, uint32(enc.GetPosition()-dstlen)) + } + t := t.Consolidations + vlen := len(t) + if vlen > 2 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2), "Consolidations") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(ConsolidationRequest) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "Consolidations[%d]", idx1) + } + } + } + { // Dynamic Field #3 'BuilderDeposits' + if canSeek { + enc.EncodeOffsetAt(offset3, uint32(enc.GetPosition()-dstlen)) + } + t := t.BuilderDeposits + vlen := len(t) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 64), "BuilderDeposits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderDepositRequest) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderDeposits[%d]", idx1) + } + } + } + { // Dynamic Field #4 'BuilderExits' + if canSeek { + enc.EncodeOffsetAt(offset4, uint32(enc.GetPosition()-dstlen)) + } + t := t.BuilderExits + vlen := len(t) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BuilderExits") + } + for idx1 := range vlen { + t := t[idx1] + if t == nil { + t = new(BuilderExitRequest) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderExits[%d]", idx1) + } + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *ExecutionRequests from SSZ-encoded bytes using dynamic specifications. +func (t *ExecutionRequests) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 20 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 20) + } + // Field #0 'Deposits' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 20 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 20), "Deposits:o") + } + // Field #1 'Withdrawals' (offset) + offset1 := int(binary.LittleEndian.Uint32(buf[4:8])) + if offset1 < offset0 || offset1 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset1, offset0, buflen), "Withdrawals:o") + } + // Field #2 'Consolidations' (offset) + offset2 := int(binary.LittleEndian.Uint32(buf[8:12])) + if offset2 < offset1 || offset2 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset2, offset1, buflen), "Consolidations:o") + } + // Field #3 'BuilderDeposits' (offset) + offset3 := int(binary.LittleEndian.Uint32(buf[12:16])) + if offset3 < offset2 || offset3 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset3, offset2, buflen), "BuilderDeposits:o") + } + // Field #4 'BuilderExits' (offset) + offset4 := int(binary.LittleEndian.Uint32(buf[16:20])) + if offset4 < offset3 || offset4 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset4, offset3, buflen), "BuilderExits:o") + } + { // Field #0 'Deposits' (dynamic) + buf := buf[offset0:offset1] + val1 := t.Deposits + itemCount := len(buf) / 192 + if len(buf)%192 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 192), "Deposits") + } + if itemCount > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 8192), "Deposits") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + for idx1 := range itemCount { + if val1[idx1] == nil { + val1[idx1] = new(DepositRequest) + } + buf := buf[192*idx1 : 192*(idx1+1)] + if err = val1[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + } + t.Deposits = val1 + } + { // Field #1 'Withdrawals' (dynamic) + buf := buf[offset1:offset2] + val2 := t.Withdrawals + itemCount := len(buf) / 76 + if len(buf)%76 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 76), "Withdrawals") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "Withdrawals") + } + val2 = sszutils.ExpandSlice(val2, itemCount) + for idx1 := range itemCount { + if val2[idx1] == nil { + val2[idx1] = new(WithdrawalRequest) + } + buf := buf[76*idx1 : 76*(idx1+1)] + if err = val2[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Withdrawals[%d]", idx1) + } + } + t.Withdrawals = val2 + } + { // Field #2 'Consolidations' (dynamic) + buf := buf[offset2:offset3] + val3 := t.Consolidations + itemCount := len(buf) / 116 + if len(buf)%116 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 116), "Consolidations") + } + if itemCount > 2 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 2), "Consolidations") + } + val3 = sszutils.ExpandSlice(val3, itemCount) + for idx1 := range itemCount { + if val3[idx1] == nil { + val3[idx1] = new(ConsolidationRequest) + } + buf := buf[116*idx1 : 116*(idx1+1)] + if err = val3[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "Consolidations[%d]", idx1) + } + } + t.Consolidations = val3 + } + { // Field #3 'BuilderDeposits' (dynamic) + buf := buf[offset3:offset4] + val4 := t.BuilderDeposits + itemCount := len(buf) / 184 + if len(buf)%184 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 184), "BuilderDeposits") + } + if itemCount > 64 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 64), "BuilderDeposits") + } + val4 = sszutils.ExpandSlice(val4, itemCount) + for idx1 := range itemCount { + if val4[idx1] == nil { + val4[idx1] = new(BuilderDepositRequest) + } + buf := buf[184*idx1 : 184*(idx1+1)] + if err = val4[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderDeposits[%d]", idx1) + } + } + t.BuilderDeposits = val4 + } + { // Field #4 'BuilderExits' (dynamic) + buf := buf[offset4:] + val5 := t.BuilderExits + itemCount := len(buf) / 68 + if len(buf)%68 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 68), "BuilderExits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "BuilderExits") + } + val5 = sszutils.ExpandSlice(val5, itemCount) + for idx1 := range itemCount { + if val5[idx1] == nil { + val5[idx1] = new(BuilderExitRequest) + } + buf := buf[68*idx1 : 68*(idx1+1)] + if err = val5[idx1].UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderExits[%d]", idx1) + } + } + t.BuilderExits = val5 + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *ExecutionRequests from the given SSZ decoder using dynamic specifications. +func (t *ExecutionRequests) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(20) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(20)) + } + // Field #0 'Deposits' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Deposits") + } + if offset0 != uint32(20) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 20), "Deposits") + } + // Field #1 'Withdrawals' (offset) + offset1, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Withdrawals") + } + if offset1 < offset0 || offset1 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset1, offset0, maxOffset), "Withdrawals") + } + // Field #2 'Consolidations' (offset) + offset2, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Consolidations") + } + if offset2 < offset1 || offset2 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset2, offset1, maxOffset), "Consolidations") + } + // Field #3 'BuilderDeposits' (offset) + offset3, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "BuilderDeposits") + } + if offset3 < offset2 || offset3 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset3, offset2, maxOffset), "BuilderDeposits") + } + // Field #4 'BuilderExits' (offset) + offset4, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "BuilderExits") + } + if offset4 < offset3 || offset4 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset4, offset3, maxOffset), "BuilderExits") + } + { // Field #0 'Deposits' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "Deposits") + } + dec.PushLimit(int(offset1 - offset0)) + val1 := t.Deposits + sszLen := dec.GetLength() + itemCount := sszLen / 192 + if sszLen%192 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 192), "Deposits") + } + if itemCount > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 8192), "Deposits") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + startPos1 := dec.GetPosition() + for idx1 := range itemCount { + if val1[idx1] == nil { + val1[idx1] = new(DepositRequest) + } + if err = val1[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + if dec.GetPosition() != startPos1+int(192*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos1+int(192*(idx1+1))), "Deposits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Deposits") + } + t.Deposits = val1 + } + { // Field #1 'Withdrawals' (dynamic) + if dec.GetPosition() != startPos0+int(offset1) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset1)), "Withdrawals") + } + dec.PushLimit(int(offset2 - offset1)) + val2 := t.Withdrawals + sszLen := dec.GetLength() + itemCount := sszLen / 76 + if sszLen%76 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 76), "Withdrawals") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "Withdrawals") + } + val2 = sszutils.ExpandSlice(val2, itemCount) + startPos2 := dec.GetPosition() + for idx1 := range itemCount { + if val2[idx1] == nil { + val2[idx1] = new(WithdrawalRequest) + } + if err = val2[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Withdrawals[%d]", idx1) + } + if dec.GetPosition() != startPos2+int(76*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos2+int(76*(idx1+1))), "Withdrawals[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Withdrawals") + } + t.Withdrawals = val2 + } + { // Field #2 'Consolidations' (dynamic) + if dec.GetPosition() != startPos0+int(offset2) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset2)), "Consolidations") + } + dec.PushLimit(int(offset3 - offset2)) + val3 := t.Consolidations + sszLen := dec.GetLength() + itemCount := sszLen / 116 + if sszLen%116 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 116), "Consolidations") + } + if itemCount > 2 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 2), "Consolidations") + } + val3 = sszutils.ExpandSlice(val3, itemCount) + startPos3 := dec.GetPosition() + for idx1 := range itemCount { + if val3[idx1] == nil { + val3[idx1] = new(ConsolidationRequest) + } + if err = val3[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "Consolidations[%d]", idx1) + } + if dec.GetPosition() != startPos3+int(116*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos3+int(116*(idx1+1))), "Consolidations[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Consolidations") + } + t.Consolidations = val3 + } + { // Field #3 'BuilderDeposits' (dynamic) + if dec.GetPosition() != startPos0+int(offset3) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset3)), "BuilderDeposits") + } + dec.PushLimit(int(offset4 - offset3)) + val4 := t.BuilderDeposits + sszLen := dec.GetLength() + itemCount := sszLen / 184 + if sszLen%184 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 184), "BuilderDeposits") + } + if itemCount > 64 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 64), "BuilderDeposits") + } + val4 = sszutils.ExpandSlice(val4, itemCount) + startPos4 := dec.GetPosition() + for idx1 := range itemCount { + if val4[idx1] == nil { + val4[idx1] = new(BuilderDepositRequest) + } + if err = val4[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderDeposits[%d]", idx1) + } + if dec.GetPosition() != startPos4+int(184*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos4+int(184*(idx1+1))), "BuilderDeposits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "BuilderDeposits") + } + t.BuilderDeposits = val4 + } + { // Field #4 'BuilderExits' (dynamic) + if dec.GetPosition() != startPos0+int(offset4) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset4)), "BuilderExits") + } + dec.PushLimit(int(maxOffset - offset4)) + val5 := t.BuilderExits + sszLen := dec.GetLength() + itemCount := sszLen / 68 + if sszLen%68 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 68), "BuilderExits") + } + if itemCount > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 16), "BuilderExits") + } + val5 = sszutils.ExpandSlice(val5, itemCount) + startPos5 := dec.GetPosition() + for idx1 := range itemCount { + if val5[idx1] == nil { + val5[idx1] = new(BuilderExitRequest) + } + if err = val5[idx1].UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderExits[%d]", idx1) + } + if dec.GetPosition() != startPos5+int(68*(idx1+1)) { + return sszutils.ErrorWithPathf(sszutils.ErrStaticElementNotConsumedFn(dec.GetPosition(), startPos5+int(68*(idx1+1))), "BuilderExits[%d]", idx1) + } + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "BuilderExits") + } + t.BuilderExits = val5 + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *ExecutionRequests. +func (t *ExecutionRequests) SizeSSZ() (size int) { + if t == nil { + t = new(ExecutionRequests) + } + // Field #0 'Deposits' offset (4 bytes) + // Field #1 'Withdrawals' offset (4 bytes) + // Field #2 'Consolidations' offset (4 bytes) + // Field #3 'BuilderDeposits' offset (4 bytes) + // Field #4 'BuilderExits' offset (4 bytes) + size += 20 + { // Dynamic field #0 'Deposits' + size += len(t.Deposits) * 192 + } + { // Dynamic field #1 'Withdrawals' + size += len(t.Withdrawals) * 76 + } + { // Dynamic field #2 'Consolidations' + size += len(t.Consolidations) * 116 + } + { // Dynamic field #3 'BuilderDeposits' + size += len(t.BuilderDeposits) * 184 + } + { // Dynamic field #4 'BuilderExits' + size += len(t.BuilderExits) * 68 + } + return size +} + +// SizeSSZDyn returns the SSZ encoded size of the *ExecutionRequests using dynamic specifications. +func (t *ExecutionRequests) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *ExecutionRequests using dynamic specifications. +func (t *ExecutionRequests) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *ExecutionRequests using dynamic specifications and the given hash walker. +func (t *ExecutionRequests) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(ExecutionRequests) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Deposits' + t := t.Deposits + vlen := uint64(len(t)) + if vlen > 8192 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 8192), "Deposits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(DepositRequest) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Deposits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #1 'Withdrawals' + t := t.Withdrawals + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "Withdrawals") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(WithdrawalRequest) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Withdrawals[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #2 'Consolidations' + t := t.Consolidations + vlen := uint64(len(t)) + if vlen > 2 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 2), "Consolidations") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(ConsolidationRequest) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "Consolidations[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #3 'BuilderDeposits' + t := t.BuilderDeposits + vlen := uint64(len(t)) + if vlen > 64 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 64), "BuilderDeposits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(BuilderDepositRequest) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderDeposits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #4 'BuilderExits' + t := t.BuilderExits + vlen := uint64(len(t)) + if vlen > 16 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 16), "BuilderExits") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + for idx1 := range int(vlen) { + t := t[idx1] + if t == nil { + t = new(BuilderExitRequest) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPathf(err, "BuilderExits[%d]", idx1) + } + if (idx1+1)%256 == 0 { + hh.Collapse() + } + } + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0x1f}) + return nil +} + +// MarshalSSZTo marshals the *DepositRequest to SSZ-encoded bytes, appending to the provided buffer. +func (t *DepositRequest) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(DepositRequest) + } + { // Static Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + dst = append(dst, t.Pubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + { // Static Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + dst = append(dst, t.WithdrawalCredentials[:vlen]...) + if vlen < 32 { + dst = sszutils.AppendZeroPadding(dst, (32-vlen)*1) + } + } + { // Static Field #2 'Amount' + dst = binary.LittleEndian.AppendUint64(dst, t.Amount) + } + { // Static Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + dst = append(dst, t.Signature[:vlen]...) + if vlen < 96 { + dst = sszutils.AppendZeroPadding(dst, (96-vlen)*1) + } + } + { // Static Field #4 'Index' + dst = binary.LittleEndian.AppendUint64(dst, t.Index) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *DepositRequest to SSZ-encoded bytes using dynamic specifications. +func (t *DepositRequest) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *DepositRequest to the given SSZ encoder using dynamic specifications. +func (t *DepositRequest) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(DepositRequest) + } + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + enc.EncodeBytes(t.Pubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + { // Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + enc.EncodeBytes(t.WithdrawalCredentials[:vlen]) + if vlen < 32 { + enc.EncodeZeroPadding((32 - vlen) * 1) + } + } + { // Field #2 'Amount' + enc.EncodeUint64(t.Amount) + } + { // Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + enc.EncodeBytes(t.Signature[:vlen]) + if vlen < 96 { + enc.EncodeZeroPadding((96 - vlen) * 1) + } + } + { // Field #4 'Index' + enc.EncodeUint64(t.Index) + } + return nil +} + +// UnmarshalSSZ unmarshals the *DepositRequest from SSZ-encoded bytes. +func (t *DepositRequest) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 192 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 192) + } + if buflen > 192 { + return sszutils.ErrTrailingDataFn(buflen - 192) + } + { // Field #0 'Pubkey' (static) + buf := buf[0:48] + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + copy(t.Pubkey[:], buf) + } + { // Field #1 'WithdrawalCredentials' (static) + buf := buf[48:80] + t.WithdrawalCredentials = sszutils.ExpandSlice(t.WithdrawalCredentials, 32) + copy(t.WithdrawalCredentials[:], buf) + } + { // Field #2 'Amount' (static) + buf := buf[80:88] + t.Amount = binary.LittleEndian.Uint64(buf) + } + { // Field #3 'Signature' (static) + buf := buf[88:184] + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + copy(t.Signature[:], buf) + } + { // Field #4 'Index' (static) + buf := buf[184:192] + t.Index = binary.LittleEndian.Uint64(buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *DepositRequest from SSZ-encoded bytes using dynamic specifications. +func (t *DepositRequest) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *DepositRequest from the given SSZ decoder using dynamic specifications. +func (t *DepositRequest) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(192) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(192)) + } + // Field #0 'Pubkey' (static) + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + if _, err = dec.DecodeBytes(t.Pubkey[:48]); err != nil { + return err + } + // Field #1 'WithdrawalCredentials' (static) + t.WithdrawalCredentials = sszutils.ExpandSlice(t.WithdrawalCredentials, 32) + if _, err = dec.DecodeBytes(t.WithdrawalCredentials[:32]); err != nil { + return err + } + // Field #2 'Amount' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Amount") + } else { + t.Amount = val + } + // Field #3 'Signature' (static) + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + // Field #4 'Index' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Index") + } else { + t.Index = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *DepositRequest. +func (t *DepositRequest) SizeSSZ() (size int) { + return 192 +} + +// SizeSSZDyn returns the SSZ encoded size of the *DepositRequest using dynamic specifications. +func (t *DepositRequest) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *DepositRequest. +func (t *DepositRequest) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *DepositRequest using the given hash walker. +func (t *DepositRequest) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(DepositRequest) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + val := t.Pubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + { // Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + val := t.WithdrawalCredentials[:] + if vlen < 32 { + val = sszutils.AppendZeroPadding(val, (32-vlen)*1) + } + hh.PutBytes(val[:32]) + } + { // Field #2 'Amount' + hh.PutUint64(t.Amount) + } + { // Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + val := t.Signature[:] + if vlen < 96 { + val = sszutils.AppendZeroPadding(val, (96-vlen)*1) + } + hh.PutBytes(val[:96]) + } + { // Field #4 'Index' + hh.PutUint64(t.Index) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *DepositRequest using dynamic specifications. +func (t *DepositRequest) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *DepositRequest using dynamic specifications and the given hash walker. +func (t *DepositRequest) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZTo marshals the *WithdrawalRequest to SSZ-encoded bytes, appending to the provided buffer. +func (t *WithdrawalRequest) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(WithdrawalRequest) + } + { // Static Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + dst = append(dst, t.SourceAddress[:vlen]...) + if vlen < 20 { + dst = sszutils.AppendZeroPadding(dst, (20-vlen)*1) + } + } + { // Static Field #1 'ValidatorPubkey' + vlen := len(t.ValidatorPubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "ValidatorPubkey") + } + dst = append(dst, t.ValidatorPubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + { // Static Field #2 'Amount' + dst = binary.LittleEndian.AppendUint64(dst, t.Amount) + } + return dst, nil +} + +// MarshalSSZDyn marshals the *WithdrawalRequest to SSZ-encoded bytes using dynamic specifications. +func (t *WithdrawalRequest) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *WithdrawalRequest to the given SSZ encoder using dynamic specifications. +func (t *WithdrawalRequest) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(WithdrawalRequest) + } + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + enc.EncodeBytes(t.SourceAddress[:vlen]) + if vlen < 20 { + enc.EncodeZeroPadding((20 - vlen) * 1) + } + } + { // Field #1 'ValidatorPubkey' + vlen := len(t.ValidatorPubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "ValidatorPubkey") + } + enc.EncodeBytes(t.ValidatorPubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + { // Field #2 'Amount' + enc.EncodeUint64(t.Amount) + } + return nil +} + +// UnmarshalSSZ unmarshals the *WithdrawalRequest from SSZ-encoded bytes. +func (t *WithdrawalRequest) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 76 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 76) + } + if buflen > 76 { + return sszutils.ErrTrailingDataFn(buflen - 76) + } + { // Field #0 'SourceAddress' (static) + buf := buf[0:20] + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + copy(t.SourceAddress[:], buf) + } + { // Field #1 'ValidatorPubkey' (static) + buf := buf[20:68] + t.ValidatorPubkey = sszutils.ExpandSlice(t.ValidatorPubkey, 48) + copy(t.ValidatorPubkey[:], buf) + } + { // Field #2 'Amount' (static) + buf := buf[68:76] + t.Amount = binary.LittleEndian.Uint64(buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *WithdrawalRequest from SSZ-encoded bytes using dynamic specifications. +func (t *WithdrawalRequest) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *WithdrawalRequest from the given SSZ decoder using dynamic specifications. +func (t *WithdrawalRequest) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(76) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(76)) + } + // Field #0 'SourceAddress' (static) + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + if _, err = dec.DecodeBytes(t.SourceAddress[:20]); err != nil { + return err + } + // Field #1 'ValidatorPubkey' (static) + t.ValidatorPubkey = sszutils.ExpandSlice(t.ValidatorPubkey, 48) + if _, err = dec.DecodeBytes(t.ValidatorPubkey[:48]); err != nil { + return err + } + // Field #2 'Amount' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Amount") + } else { + t.Amount = val + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *WithdrawalRequest. +func (t *WithdrawalRequest) SizeSSZ() (size int) { + return 76 +} + +// SizeSSZDyn returns the SSZ encoded size of the *WithdrawalRequest using dynamic specifications. +func (t *WithdrawalRequest) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *WithdrawalRequest. +func (t *WithdrawalRequest) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *WithdrawalRequest using the given hash walker. +func (t *WithdrawalRequest) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(WithdrawalRequest) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + val := t.SourceAddress[:] + if vlen < 20 { + val = sszutils.AppendZeroPadding(val, (20-vlen)*1) + } + hh.PutBytes(val[:20]) + } + { // Field #1 'ValidatorPubkey' + vlen := len(t.ValidatorPubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "ValidatorPubkey") + } + val := t.ValidatorPubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + { // Field #2 'Amount' + hh.PutUint64(t.Amount) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *WithdrawalRequest using dynamic specifications. +func (t *WithdrawalRequest) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *WithdrawalRequest using dynamic specifications and the given hash walker. +func (t *WithdrawalRequest) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZTo marshals the *ConsolidationRequest to SSZ-encoded bytes, appending to the provided buffer. +func (t *ConsolidationRequest) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(ConsolidationRequest) + } + { // Static Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + dst = append(dst, t.SourceAddress[:vlen]...) + if vlen < 20 { + dst = sszutils.AppendZeroPadding(dst, (20-vlen)*1) + } + } + { // Static Field #1 'SourcePubkey' + vlen := len(t.SourcePubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "SourcePubkey") + } + dst = append(dst, t.SourcePubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + { // Static Field #2 'TargetPubkey' + vlen := len(t.TargetPubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "TargetPubkey") + } + dst = append(dst, t.TargetPubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + return dst, nil +} + +// MarshalSSZDyn marshals the *ConsolidationRequest to SSZ-encoded bytes using dynamic specifications. +func (t *ConsolidationRequest) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *ConsolidationRequest to the given SSZ encoder using dynamic specifications. +func (t *ConsolidationRequest) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(ConsolidationRequest) + } + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + enc.EncodeBytes(t.SourceAddress[:vlen]) + if vlen < 20 { + enc.EncodeZeroPadding((20 - vlen) * 1) + } + } + { // Field #1 'SourcePubkey' + vlen := len(t.SourcePubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "SourcePubkey") + } + enc.EncodeBytes(t.SourcePubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + { // Field #2 'TargetPubkey' + vlen := len(t.TargetPubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "TargetPubkey") + } + enc.EncodeBytes(t.TargetPubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + return nil +} + +// UnmarshalSSZ unmarshals the *ConsolidationRequest from SSZ-encoded bytes. +func (t *ConsolidationRequest) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 116 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 116) + } + if buflen > 116 { + return sszutils.ErrTrailingDataFn(buflen - 116) + } + { // Field #0 'SourceAddress' (static) + buf := buf[0:20] + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + copy(t.SourceAddress[:], buf) + } + { // Field #1 'SourcePubkey' (static) + buf := buf[20:68] + t.SourcePubkey = sszutils.ExpandSlice(t.SourcePubkey, 48) + copy(t.SourcePubkey[:], buf) + } + { // Field #2 'TargetPubkey' (static) + buf := buf[68:116] + t.TargetPubkey = sszutils.ExpandSlice(t.TargetPubkey, 48) + copy(t.TargetPubkey[:], buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *ConsolidationRequest from SSZ-encoded bytes using dynamic specifications. +func (t *ConsolidationRequest) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *ConsolidationRequest from the given SSZ decoder using dynamic specifications. +func (t *ConsolidationRequest) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(116) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(116)) + } + // Field #0 'SourceAddress' (static) + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + if _, err = dec.DecodeBytes(t.SourceAddress[:20]); err != nil { + return err + } + // Field #1 'SourcePubkey' (static) + t.SourcePubkey = sszutils.ExpandSlice(t.SourcePubkey, 48) + if _, err = dec.DecodeBytes(t.SourcePubkey[:48]); err != nil { + return err + } + // Field #2 'TargetPubkey' (static) + t.TargetPubkey = sszutils.ExpandSlice(t.TargetPubkey, 48) + if _, err = dec.DecodeBytes(t.TargetPubkey[:48]); err != nil { + return err + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *ConsolidationRequest. +func (t *ConsolidationRequest) SizeSSZ() (size int) { + return 116 +} + +// SizeSSZDyn returns the SSZ encoded size of the *ConsolidationRequest using dynamic specifications. +func (t *ConsolidationRequest) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *ConsolidationRequest. +func (t *ConsolidationRequest) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *ConsolidationRequest using the given hash walker. +func (t *ConsolidationRequest) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(ConsolidationRequest) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + val := t.SourceAddress[:] + if vlen < 20 { + val = sszutils.AppendZeroPadding(val, (20-vlen)*1) + } + hh.PutBytes(val[:20]) + } + { // Field #1 'SourcePubkey' + vlen := len(t.SourcePubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "SourcePubkey") + } + val := t.SourcePubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + { // Field #2 'TargetPubkey' + vlen := len(t.TargetPubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "TargetPubkey") + } + val := t.TargetPubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *ConsolidationRequest using dynamic specifications. +func (t *ConsolidationRequest) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *ConsolidationRequest using dynamic specifications and the given hash walker. +func (t *ConsolidationRequest) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZTo marshals the *BuilderDepositRequest to SSZ-encoded bytes, appending to the provided buffer. +func (t *BuilderDepositRequest) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(BuilderDepositRequest) + } + { // Static Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + dst = append(dst, t.Pubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + { // Static Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + dst = append(dst, t.WithdrawalCredentials[:vlen]...) + if vlen < 32 { + dst = sszutils.AppendZeroPadding(dst, (32-vlen)*1) + } + } + { // Static Field #2 'Amount' + dst = binary.LittleEndian.AppendUint64(dst, t.Amount) + } + { // Static Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + dst = append(dst, t.Signature[:vlen]...) + if vlen < 96 { + dst = sszutils.AppendZeroPadding(dst, (96-vlen)*1) + } + } + return dst, nil +} + +// MarshalSSZDyn marshals the *BuilderDepositRequest to SSZ-encoded bytes using dynamic specifications. +func (t *BuilderDepositRequest) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *BuilderDepositRequest to the given SSZ encoder using dynamic specifications. +func (t *BuilderDepositRequest) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(BuilderDepositRequest) + } + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + enc.EncodeBytes(t.Pubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + { // Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + enc.EncodeBytes(t.WithdrawalCredentials[:vlen]) + if vlen < 32 { + enc.EncodeZeroPadding((32 - vlen) * 1) + } + } + { // Field #2 'Amount' + enc.EncodeUint64(t.Amount) + } + { // Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + enc.EncodeBytes(t.Signature[:vlen]) + if vlen < 96 { + enc.EncodeZeroPadding((96 - vlen) * 1) + } + } + return nil +} + +// UnmarshalSSZ unmarshals the *BuilderDepositRequest from SSZ-encoded bytes. +func (t *BuilderDepositRequest) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 184 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 184) + } + if buflen > 184 { + return sszutils.ErrTrailingDataFn(buflen - 184) + } + { // Field #0 'Pubkey' (static) + buf := buf[0:48] + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + copy(t.Pubkey[:], buf) + } + { // Field #1 'WithdrawalCredentials' (static) + buf := buf[48:80] + t.WithdrawalCredentials = sszutils.ExpandSlice(t.WithdrawalCredentials, 32) + copy(t.WithdrawalCredentials[:], buf) + } + { // Field #2 'Amount' (static) + buf := buf[80:88] + t.Amount = binary.LittleEndian.Uint64(buf) + } + { // Field #3 'Signature' (static) + buf := buf[88:184] + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + copy(t.Signature[:], buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BuilderDepositRequest from SSZ-encoded bytes using dynamic specifications. +func (t *BuilderDepositRequest) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *BuilderDepositRequest from the given SSZ decoder using dynamic specifications. +func (t *BuilderDepositRequest) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(184) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(184)) + } + // Field #0 'Pubkey' (static) + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + if _, err = dec.DecodeBytes(t.Pubkey[:48]); err != nil { + return err + } + // Field #1 'WithdrawalCredentials' (static) + t.WithdrawalCredentials = sszutils.ExpandSlice(t.WithdrawalCredentials, 32) + if _, err = dec.DecodeBytes(t.WithdrawalCredentials[:32]); err != nil { + return err + } + // Field #2 'Amount' (static) + if val, err := dec.DecodeUint64(); err != nil { + return sszutils.ErrorWithPath(err, "Amount") + } else { + t.Amount = val + } + // Field #3 'Signature' (static) + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *BuilderDepositRequest. +func (t *BuilderDepositRequest) SizeSSZ() (size int) { + return 184 +} + +// SizeSSZDyn returns the SSZ encoded size of the *BuilderDepositRequest using dynamic specifications. +func (t *BuilderDepositRequest) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *BuilderDepositRequest. +func (t *BuilderDepositRequest) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *BuilderDepositRequest using the given hash walker. +func (t *BuilderDepositRequest) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(BuilderDepositRequest) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + val := t.Pubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + { // Field #1 'WithdrawalCredentials' + vlen := len(t.WithdrawalCredentials) + if vlen > 32 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 32), "WithdrawalCredentials") + } + val := t.WithdrawalCredentials[:] + if vlen < 32 { + val = sszutils.AppendZeroPadding(val, (32-vlen)*1) + } + hh.PutBytes(val[:32]) + } + { // Field #2 'Amount' + hh.PutUint64(t.Amount) + } + { // Field #3 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + val := t.Signature[:] + if vlen < 96 { + val = sszutils.AppendZeroPadding(val, (96-vlen)*1) + } + hh.PutBytes(val[:96]) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BuilderDepositRequest using dynamic specifications. +func (t *BuilderDepositRequest) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BuilderDepositRequest using dynamic specifications and the given hash walker. +func (t *BuilderDepositRequest) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZTo marshals the *BuilderExitRequest to SSZ-encoded bytes, appending to the provided buffer. +func (t *BuilderExitRequest) MarshalSSZTo(buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(BuilderExitRequest) + } + { // Static Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + dst = append(dst, t.SourceAddress[:vlen]...) + if vlen < 20 { + dst = sszutils.AppendZeroPadding(dst, (20-vlen)*1) + } + } + { // Static Field #1 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + dst = append(dst, t.Pubkey[:vlen]...) + if vlen < 48 { + dst = sszutils.AppendZeroPadding(dst, (48-vlen)*1) + } + } + return dst, nil +} + +// MarshalSSZDyn marshals the *BuilderExitRequest to SSZ-encoded bytes using dynamic specifications. +func (t *BuilderExitRequest) MarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + return t.MarshalSSZTo(buf) +} + +// MarshalSSZEncoder marshals the *BuilderExitRequest to the given SSZ encoder using dynamic specifications. +func (t *BuilderExitRequest) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + if t == nil { + t = new(BuilderExitRequest) + } + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + enc.EncodeBytes(t.SourceAddress[:vlen]) + if vlen < 20 { + enc.EncodeZeroPadding((20 - vlen) * 1) + } + } + { // Field #1 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + enc.EncodeBytes(t.Pubkey[:vlen]) + if vlen < 48 { + enc.EncodeZeroPadding((48 - vlen) * 1) + } + } + return nil +} + +// UnmarshalSSZ unmarshals the *BuilderExitRequest from SSZ-encoded bytes. +func (t *BuilderExitRequest) UnmarshalSSZ(buf []byte) (err error) { + buflen := len(buf) + if buflen < 68 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 68) + } + if buflen > 68 { + return sszutils.ErrTrailingDataFn(buflen - 68) + } + { // Field #0 'SourceAddress' (static) + buf := buf[0:20] + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + copy(t.SourceAddress[:], buf) + } + { // Field #1 'Pubkey' (static) + buf := buf[20:68] + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + copy(t.Pubkey[:], buf) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *BuilderExitRequest from SSZ-encoded bytes using dynamic specifications. +func (t *BuilderExitRequest) UnmarshalSSZDyn(_ sszutils.DynamicSpecs, buf []byte) (err error) { + return t.UnmarshalSSZ(buf) +} + +// UnmarshalSSZDecoder unmarshals the *BuilderExitRequest from the given SSZ decoder using dynamic specifications. +func (t *BuilderExitRequest) UnmarshalSSZDecoder(_ sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + if maxOffset < uint32(68) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(68)) + } + // Field #0 'SourceAddress' (static) + t.SourceAddress = sszutils.ExpandSlice(t.SourceAddress, 20) + if _, err = dec.DecodeBytes(t.SourceAddress[:20]); err != nil { + return err + } + // Field #1 'Pubkey' (static) + t.Pubkey = sszutils.ExpandSlice(t.Pubkey, 48) + if _, err = dec.DecodeBytes(t.Pubkey[:48]); err != nil { + return err + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *BuilderExitRequest. +func (t *BuilderExitRequest) SizeSSZ() (size int) { + return 68 +} + +// SizeSSZDyn returns the SSZ encoded size of the *BuilderExitRequest using dynamic specifications. +func (t *BuilderExitRequest) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRoot computes the SSZ hash tree root of the *BuilderExitRequest. +func (t *BuilderExitRequest) HashTreeRoot() (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWith(hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWith computes the SSZ hash tree root of the *BuilderExitRequest using the given hash walker. +func (t *BuilderExitRequest) HashTreeRootWith(hh sszutils.HashWalker) error { + if t == nil { + t = new(BuilderExitRequest) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'SourceAddress' + vlen := len(t.SourceAddress) + if vlen > 20 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 20), "SourceAddress") + } + val := t.SourceAddress[:] + if vlen < 20 { + val = sszutils.AppendZeroPadding(val, (20-vlen)*1) + } + hh.PutBytes(val[:20]) + } + { // Field #1 'Pubkey' + vlen := len(t.Pubkey) + if vlen > 48 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 48), "Pubkey") + } + val := t.Pubkey[:] + if vlen < 48 { + val = sszutils.AppendZeroPadding(val, (48-vlen)*1) + } + hh.PutBytes(val[:48]) + } + hh.Merkleize(idx) + return nil +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *BuilderExitRequest using dynamic specifications. +func (t *BuilderExitRequest) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *BuilderExitRequest using dynamic specifications and the given hash walker. +func (t *BuilderExitRequest) HashTreeRootWithDyn(_ sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + return t.HashTreeRootWith(hh) +} + +// MarshalSSZDyn marshals the *AttesterSlashing to SSZ-encoded bytes using dynamic specifications. +func (t *AttesterSlashing) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(AttesterSlashing) + } + dstlen := len(dst) + // Offset Field #0 'Attestation1' + // Offset Field #1 'Attestation2' + dst = append(dst, 0, 0, 0, 0, 0, 0, 0, 0) + { // Dynamic Field #0 'Attestation1' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.Attestation1 + if t == nil { + t = new(IndexedAttestation) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Attestation1") + } + } + { // Dynamic Field #1 'Attestation2' + binary.LittleEndian.PutUint32(dst[dstlen+4:], uint32(len(dst)-dstlen)) + t := t.Attestation2 + if t == nil { + t = new(IndexedAttestation) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Attestation2") + } + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *AttesterSlashing to the given SSZ encoder using dynamic specifications. +func (t *AttesterSlashing) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t *IndexedAttestation) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for *IndexedAttestation + ctx.sizeFn1 = func(ctx *encoderCtx, t *IndexedAttestation) (size int) { + size += t.SizeSSZDyn(ds) + return size + } + if t == nil { + t = new(AttesterSlashing) + } + dstlen := enc.GetPosition() + dynoff := uint32(8) + // Offset #0 'Attestation1' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Attestation1)) + } + // Offset #1 'Attestation2' + offset1 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.Attestation2)) + } + { // Dynamic Field #0 'Attestation1' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.Attestation1 + if t == nil { + t = new(IndexedAttestation) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Attestation1") + } + } + { // Dynamic Field #1 'Attestation2' + if canSeek { + enc.EncodeOffsetAt(offset1, uint32(enc.GetPosition()-dstlen)) + } + t := t.Attestation2 + if t == nil { + t = new(IndexedAttestation) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Attestation2") + } + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *AttesterSlashing from SSZ-encoded bytes using dynamic specifications. +func (t *AttesterSlashing) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 8 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 8) + } + // Field #0 'Attestation1' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 8 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 8), "Attestation1:o") + } + // Field #1 'Attestation2' (offset) + offset1 := int(binary.LittleEndian.Uint32(buf[4:8])) + if offset1 < offset0 || offset1 > buflen { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset1, offset0, buflen), "Attestation2:o") + } + { // Field #0 'Attestation1' (dynamic) + buf := buf[offset0:offset1] + if t.Attestation1 == nil { + t.Attestation1 = new(IndexedAttestation) + } + if err = t.Attestation1.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Attestation1") + } + } + { // Field #1 'Attestation2' (dynamic) + buf := buf[offset1:] + if t.Attestation2 == nil { + t.Attestation2 = new(IndexedAttestation) + } + if err = t.Attestation2.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Attestation2") + } + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *AttesterSlashing from the given SSZ decoder using dynamic specifications. +func (t *AttesterSlashing) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(8) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(8)) + } + // Field #0 'Attestation1' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Attestation1") + } + if offset0 != uint32(8) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 8), "Attestation1") + } + // Field #1 'Attestation2' (offset) + offset1, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "Attestation2") + } + if offset1 < offset0 || offset1 > maxOffset { + return sszutils.ErrorWithPath(sszutils.ErrOffsetOutOfRangeFn(offset1, offset0, maxOffset), "Attestation2") + } + { // Field #0 'Attestation1' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "Attestation1") + } + dec.PushLimit(int(offset1 - offset0)) + val1 := t.Attestation1 + if val1 == nil { + val1 = new(IndexedAttestation) + } + if err = val1.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Attestation1") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Attestation1") + } + t.Attestation1 = val1 + } + { // Field #1 'Attestation2' (dynamic) + if dec.GetPosition() != startPos0+int(offset1) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset1)), "Attestation2") + } + dec.PushLimit(int(maxOffset - offset1)) + val2 := t.Attestation2 + if val2 == nil { + val2 = new(IndexedAttestation) + } + if err = val2.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Attestation2") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "Attestation2") + } + t.Attestation2 = val2 + } + return nil +} + +// SizeSSZDyn returns the SSZ encoded size of the *AttesterSlashing using dynamic specifications. +func (t *AttesterSlashing) SizeSSZDyn(ds sszutils.DynamicSpecs) (size int) { + if t == nil { + t = new(AttesterSlashing) + } + // Field #0 'Attestation1' offset (4 bytes) + // Field #1 'Attestation2' offset (4 bytes) + size += 8 + { // Dynamic field #0 'Attestation1' + size += t.Attestation1.SizeSSZDyn(ds) + } + { // Dynamic field #1 'Attestation2' + size += t.Attestation2.SizeSSZDyn(ds) + } + return size +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *AttesterSlashing using dynamic specifications. +func (t *AttesterSlashing) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *AttesterSlashing using dynamic specifications and the given hash walker. +func (t *AttesterSlashing) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(AttesterSlashing) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'Attestation1' + t := t.Attestation1 + if t == nil { + t = new(IndexedAttestation) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Attestation1") + } + } + { // Field #1 'Attestation2' + t := t.Attestation2 + if t == nil { + t = new(IndexedAttestation) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Attestation2") + } + } + hh.Merkleize(idx) + return nil +} + +// MarshalSSZDyn marshals the *IndexedAttestation to SSZ-encoded bytes using dynamic specifications. +func (t *IndexedAttestation) MarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (dst []byte, err error) { + dst = buf + if t == nil { + t = new(IndexedAttestation) + } + dstlen := len(dst) + // Offset Field #0 'AttestingIndices' + dst = append(dst, 0, 0, 0, 0) + { // Static Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if dst, err = t.MarshalSSZDyn(ds, dst); err != nil { + return nil, sszutils.ErrorWithPath(err, "Data") + } + } + { // Static Field #2 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return nil, sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + dst = append(dst, t.Signature[:vlen]...) + if vlen < 96 { + dst = sszutils.AppendZeroPadding(dst, (96-vlen)*1) + } + } + { // Dynamic Field #0 'AttestingIndices' + binary.LittleEndian.PutUint32(dst[dstlen:], uint32(len(dst)-dstlen)) + t := t.AttestingIndices + vlen := len(t) + if vlen > 131072 { + return nil, sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 131072), "AttestingIndices") + } + dst = sszutils.MarshalUint64Slice(dst, t[:vlen]) + } + return dst, nil +} + +// MarshalSSZEncoder marshals the *IndexedAttestation to the given SSZ encoder using dynamic specifications. +func (t *IndexedAttestation) MarshalSSZEncoder(ds sszutils.DynamicSpecs, enc sszutils.Encoder) (err error) { + type encoderCtx struct { + ds sszutils.DynamicSpecs + exprs [0]uint64 + sizeFn1 func(ctx *encoderCtx, t []uint64) (size int) + } + ctx := &encoderCtx{ds: ds} + canSeek := enc.Seekable() + // size for []uint64 + ctx.sizeFn1 = func(ctx *encoderCtx, t []uint64) (size int) { + size += len(t) * 8 + return size + } + if t == nil { + t = new(IndexedAttestation) + } + dstlen := enc.GetPosition() + dynoff := uint32(228) + // Offset #0 'AttestingIndices' + offset0 := enc.GetPosition() + if canSeek { + enc.EncodeOffset(0) + } else { + enc.EncodeOffset(dynoff) + dynoff += uint32(ctx.sizeFn1(ctx, t.AttestingIndices)) + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if err = t.MarshalSSZEncoder(ds, enc); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + enc.EncodeBytes(t.Signature[:vlen]) + if vlen < 96 { + enc.EncodeZeroPadding((96 - vlen) * 1) + } + } + { // Dynamic Field #0 'AttestingIndices' + if canSeek { + enc.EncodeOffsetAt(offset0, uint32(enc.GetPosition()-dstlen)) + } + t := t.AttestingIndices + vlen := len(t) + if vlen > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 131072), "AttestingIndices") + } + sszutils.EncodeUint64Slice(enc, t[:vlen]) + } + return nil +} + +// UnmarshalSSZDyn unmarshals the *IndexedAttestation from SSZ-encoded bytes using dynamic specifications. +func (t *IndexedAttestation) UnmarshalSSZDyn(ds sszutils.DynamicSpecs, buf []byte) (err error) { + buflen := len(buf) + if buflen < 228 { + return sszutils.ErrFixedFieldsEOFFn(buflen, 228) + } + // Field #0 'AttestingIndices' (offset) + offset0 := int(binary.LittleEndian.Uint32(buf[0:4])) + if offset0 != 228 { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 228), "AttestingIndices:o") + } + { // Field #1 'Data' (static) + buf := buf[4:132] + if t.Data == nil { + t.Data = new(generic.AttestationData) + } + if err = t.Data.UnmarshalSSZDyn(ds, buf); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' (static) + buf := buf[132:228] + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + copy(t.Signature[:], buf) + } + { // Field #0 'AttestingIndices' (dynamic) + buf := buf[offset0:] + val1 := t.AttestingIndices + itemCount := len(buf) / 8 + if len(buf)%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(len(buf), 8), "AttestingIndices") + } + if itemCount > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 131072), "AttestingIndices") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + sszutils.UnmarshalUint64Slice(val1, buf) + t.AttestingIndices = val1 + } + return nil +} + +// UnmarshalSSZDecoder unmarshals the *IndexedAttestation from the given SSZ decoder using dynamic specifications. +func (t *IndexedAttestation) UnmarshalSSZDecoder(ds sszutils.DynamicSpecs, dec sszutils.Decoder) (err error) { + maxOffset := uint32(dec.GetLength()) + startPos0 := dec.GetPosition() + if maxOffset < uint32(228) { + return sszutils.ErrFixedFieldsEOFFn(maxOffset, uint32(228)) + } + // Field #0 'AttestingIndices' (offset) + offset0, err := dec.DecodeOffset() + if err != nil { + return sszutils.ErrorWithPath(err, "AttestingIndices") + } + if offset0 != uint32(228) { + return sszutils.ErrorWithPath(sszutils.ErrFirstOffsetMismatchFn(offset0, 228), "AttestingIndices") + } + // Field #1 'Data' (static) + if t.Data == nil { + t.Data = new(generic.AttestationData) + } + if err = t.Data.UnmarshalSSZDecoder(ds, dec); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + // Field #2 'Signature' (static) + t.Signature = sszutils.ExpandSlice(t.Signature, 96) + if _, err = dec.DecodeBytes(t.Signature[:96]); err != nil { + return err + } + { // Field #0 'AttestingIndices' (dynamic) + if dec.GetPosition() != startPos0+int(offset0) { + return sszutils.ErrorWithPath(sszutils.ErrFieldNotConsumedFn(dec.GetPosition(), startPos0+int(offset0)), "AttestingIndices") + } + dec.PushLimit(int(maxOffset - offset0)) + val1 := t.AttestingIndices + sszLen := dec.GetLength() + itemCount := sszLen / 8 + if sszLen%8 != 0 { + return sszutils.ErrorWithPath(sszutils.ErrListNotAlignedFn(sszLen, 8), "AttestingIndices") + } + if itemCount > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(itemCount, 131072), "AttestingIndices") + } + val1 = sszutils.ExpandSlice(val1, itemCount) + if err = sszutils.DecodeUint64Slice(dec, val1); err != nil { + return sszutils.ErrorWithPath(err, "AttestingIndices") + } + if diff := dec.PopLimit(); diff != 0 { + return sszutils.ErrorWithPath(sszutils.ErrTrailingDataFn(diff), "AttestingIndices") + } + t.AttestingIndices = val1 + } + return nil +} + +// SizeSSZ returns the SSZ encoded size of the *IndexedAttestation. +func (t *IndexedAttestation) SizeSSZ() (size int) { + if t == nil { + t = new(IndexedAttestation) + } + // Field #0 'AttestingIndices' offset (4 bytes) + // Field #1 'Data' static (128 bytes) + // Field #2 'Signature' static (96 bytes) + size += 228 + { // Dynamic field #0 'AttestingIndices' + size += len(t.AttestingIndices) * 8 + } + return size +} + +// SizeSSZDyn returns the SSZ encoded size of the *IndexedAttestation using dynamic specifications. +func (t *IndexedAttestation) SizeSSZDyn(_ sszutils.DynamicSpecs) (size int) { + return t.SizeSSZ() +} + +// HashTreeRootDyn computes the SSZ hash tree root of the *IndexedAttestation using dynamic specifications. +func (t *IndexedAttestation) HashTreeRootDyn(ds sszutils.DynamicSpecs) (root [32]byte, err error) { + err = hasher.WithDefaultHasher(func(hh sszutils.HashWalker) (err error) { + err = t.HashTreeRootWithDyn(ds, hh) + if err == nil { + root, err = hh.HashRoot() + } + return + }) + return +} + +// HashTreeRootWithDyn computes the SSZ hash tree root of the *IndexedAttestation using dynamic specifications and the given hash walker. +func (t *IndexedAttestation) HashTreeRootWithDyn(ds sszutils.DynamicSpecs, hh sszutils.HashWalker) error { + if t == nil { + t = new(IndexedAttestation) + } + idx := hh.StartTree(sszutils.TreeTypeNone) + { // Field #0 'AttestingIndices' + t := t.AttestingIndices + vlen := uint64(len(t)) + if vlen > 131072 { + return sszutils.ErrorWithPath(sszutils.ErrListLengthFn(vlen, 131072), "AttestingIndices") + } + idx := hh.StartTree(sszutils.TreeTypeProgressive) + sszutils.HashUint64Slice(hh, t) + hh.FillUpTo32() + hh.MerkleizeProgressiveWithMixin(idx, vlen) + } + { // Field #1 'Data' + t := t.Data + if t == nil { + t = new(generic.AttestationData) + } + if err := t.HashTreeRootWithDyn(ds, hh); err != nil { + return sszutils.ErrorWithPath(err, "Data") + } + } + { // Field #2 'Signature' + vlen := len(t.Signature) + if vlen > 96 { + return sszutils.ErrorWithPath(sszutils.ErrVectorLengthFn(vlen, 96), "Signature") + } + val := t.Signature[:] + if vlen < 96 { + val = sszutils.AppendZeroPadding(val, (96-vlen)*1) + } + hh.PutBytes(val[:96]) + } + hh.MerkleizeProgressiveWithActiveFields(idx, []byte{0x07}) + return nil +} diff --git a/shared/types/eth2/fork/gloas/gloas_proofs_test.go b/shared/types/eth2/fork/gloas/gloas_proofs_test.go new file mode 100644 index 000000000..f809807d5 --- /dev/null +++ b/shared/types/eth2/fork/gloas/gloas_proofs_test.go @@ -0,0 +1,365 @@ +package gloas + +import ( + "bytes" + "testing" + + "github.com/pk910/dynamic-ssz/treeproof" + + "github.com/rocket-pool/smartnode/shared/types/eth2/generic" +) + +func TestGloasFieldGindices(t *testing.T) { + // Stable progressive field gindices for Gloas BeaconState (ssz-index → absolute). + cases := []struct { + name string + got uint64 + want uint64 + }{ + {"slot", GetGeneralizedIndexForSlot(), 41}, + {"block_roots", GetGeneralizedIndexForBlockRoots(), 352}, + {"validators", GetGeneralizedIndexForValidators(), 358}, + {"historical_summaries", GetGeneralizedIndexForHistoricalSummaries(), 2950}, + {"validators[0]", GetGeneralizedIndexForValidator(0), 1432}, + {"validators[1]", GetGeneralizedIndexForValidator(1), 11464}, + } + for _, tc := range cases { + if tc.got != tc.want { + t.Errorf("%s: got %d want %d", tc.name, tc.got, tc.want) + } + } +} + +func TestValidatorAndSlotProofProgressive(t *testing.T) { + state := minimalBeaconState() + state.Slot = 100 + state.Validators = []*generic.Validator{ + { + Pubkey: bytes.Repeat([]byte{0x01}, 48), + WithdrawalCredentials: bytes.Repeat([]byte{0x02}, 32), + EffectiveBalance: 32_000_000_000, + }, + { + Pubkey: bytes.Repeat([]byte{0x03}, 48), + WithdrawalCredentials: bytes.Repeat([]byte{0x04}, 32), + EffectiveBalance: 31_000_000_000, + }, + } + state.Balances = []uint64{32_000_000_000, 31_000_000_000} + + // Prove validators[1] and slot against the state tree (without block-header extension). + stateTree, err := generic.SSZ.GetTree(state) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + stateRoot := stateTree.Hash() + + validatorGid := GetGeneralizedIndexForValidator(1) + validatorProof, err := stateTree.Prove(int(validatorGid)) + if err != nil { + t.Fatalf("Prove validator: %v", err) + } + validatorLeaf, err := generic.SSZ.HashTreeRoot(state.Validators[1]) + if err != nil { + t.Fatalf("validator HTR: %v", err) + } + if !bytes.Equal(validatorProof.Leaf, validatorLeaf[:]) { + t.Fatalf("validator leaf mismatch") + } + if ok, err := treeproof.VerifyProof(stateRoot, validatorProof); err != nil || !ok { + t.Fatalf("verify validator proof: ok=%v err=%v", ok, err) + } + + slotProof, err := stateTree.Prove(int(GetGeneralizedIndexForSlot())) + if err != nil { + t.Fatalf("Prove slot: %v", err) + } + if ok, err := treeproof.VerifyProof(stateRoot, slotProof); err != nil || !ok { + t.Fatalf("verify slot proof: ok=%v err=%v", ok, err) + } + + // Full ValidatorAndSlotProof (state + block header extension) should succeed. + vProof, sProof, err := state.ValidatorAndSlotProof(1) + if err != nil { + t.Fatalf("ValidatorAndSlotProof: %v", err) + } + if len(vProof) == 0 || len(sProof) == 0 { + t.Fatalf("expected non-empty proofs, got validator=%d slot=%d", len(vProof), len(sProof)) + } + // Block-header extension adds the same suffix to both proofs. + if len(vProof) <= len(validatorProof.Hashes) { + t.Fatalf("expected block-header extension on validator proof") + } +} + +func TestBlockRootProofProgressive(t *testing.T) { + state := minimalBeaconState() + // Slot far enough that block_roots[slot % 8192] is still "recent". + state.Slot = 100 + // Plant a distinctive root at index 10. + var planted [32]byte + for i := range planted { + planted[i] = byte(i + 1) + } + state.BlockRoots[10] = planted + + tree, err := generic.SSZ.GetTree(state) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + + // Prove block_roots[10] via the helper (uses progressive field gindex + vector). + proofHashes, err := state.BlockRootProof(10) + if err != nil { + t.Fatalf("BlockRootProof: %v", err) + } + + gid := generic.GetGeneralizedIndexForVectorElement( + GetGeneralizedIndexForBlockRoots(), + generic.BeaconStateBlockRootsMaxLength, + 10, + ) + direct, err := tree.Prove(int(gid)) + if err != nil { + t.Fatalf("direct Prove: %v", err) + } + if !bytes.Equal(direct.Leaf, planted[:]) { + t.Fatalf("leaf mismatch: got %x want %x", direct.Leaf, planted) + } + if ok, err := treeproof.VerifyProof(tree.Hash(), direct); err != nil || !ok { + t.Fatalf("verify block root: ok=%v err=%v", ok, err) + } + if len(proofHashes) != len(direct.Hashes) { + t.Fatalf("helper proof length %d != direct %d", len(proofHashes), len(direct.Hashes)) + } + for i := range proofHashes { + if !bytes.Equal(proofHashes[i], direct.Hashes[i]) { + t.Fatalf("proof hash[%d] mismatch", i) + } + } +} + +func TestHistoricalSummaryProofProgressive(t *testing.T) { + state := minimalBeaconState() + // Historical: slot + 8192 <= state.Slot + state.Slot = generic.SlotsPerHistoricalRoot + 100 + summary := &generic.HistoricalSummary{ + BlockSummaryRoot: [32]byte{0xaa}, + StateSummaryRoot: [32]byte{0xbb}, + } + state.HistoricalSummaries = []*generic.HistoricalSummary{summary} + + tree, err := generic.SSZ.GetTree(state) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + + // Prove historical_summaries[0] for slot 0 with capellaOffset 0. + arrayIndex := uint64(0) + gid := generic.GetGeneralizedIndexForListElement( + GetGeneralizedIndexForHistoricalSummaries(), + generic.BeaconStateHistoricalSummariesMaxLength, + arrayIndex, + ) + proof, err := tree.Prove(int(gid)) + if err != nil { + t.Fatalf("Prove historical summary: %v", err) + } + summaryRoot, err := generic.SSZ.HashTreeRoot(summary) + if err != nil { + t.Fatalf("summary HTR: %v", err) + } + if !bytes.Equal(proof.Leaf, summaryRoot[:]) { + t.Fatalf("summary leaf mismatch") + } + if ok, err := treeproof.VerifyProof(tree.Hash(), proof); err != nil || !ok { + t.Fatalf("verify historical summary: ok=%v err=%v", ok, err) + } + + // Helper should also succeed (includes block-header extension). + hashes, err := state.HistoricalSummaryProof(0, 0) + if err != nil { + t.Fatalf("HistoricalSummaryProof: %v", err) + } + if len(hashes) <= len(proof.Hashes) { + t.Fatalf("expected block-header extension on historical summary proof") + } +} + +func TestGloasWithdrawalProofGindices(t *testing.T) { + // Stable progressive field gindices for the Gloas withdrawal-proof path + // (ssz-index → absolute). + cases := []struct { + name string + got uint64 + want uint64 + }{ + {"state_roots", GetGeneralizedIndexForStateRoots(), 353}, + {"payload_expected_withdrawals", GetGeneralizedIndexForPayloadExpectedWithdrawals(), 2967}, + {"payload_expected_withdrawals[0]", GetGeneralizedIndexForExpectedWithdrawal(0), 11868}, + {"payload_expected_withdrawals[1]", GetGeneralizedIndexForExpectedWithdrawal(1), 94952}, + } + for _, tc := range cases { + if tc.got != tc.want { + t.Errorf("%s: got %d want %d", tc.name, tc.got, tc.want) + } + } +} + +func TestProveExpectedWithdrawal(t *testing.T) { + state := minimalBeaconState() + state.Slot = 100 + state.PayloadExpectedWithdrawals = []*generic.Withdrawal{ + {Index: 10, ValidatorIndex: 5, Address: [20]byte{0xaa}, Amount: 32_000_000_000}, + {Index: 11, ValidatorIndex: 7, Address: [20]byte{0xbb}, Amount: 1_000_000_000}, + } + + stateTree, err := generic.SSZ.GetTree(state) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + stateRoot := stateTree.Hash() + + // Prove payload_expected_withdrawals[1] via the helper. + proofHashes, err := state.ProveExpectedWithdrawal(1) + if err != nil { + t.Fatalf("ProveExpectedWithdrawal: %v", err) + } + + // Compare against a direct tree proof at the expected gindex. + gid := GetGeneralizedIndexForExpectedWithdrawal(1) + direct, err := stateTree.Prove(int(gid)) + if err != nil { + t.Fatalf("direct Prove: %v", err) + } + leaf, err := generic.SSZ.HashTreeRoot(state.PayloadExpectedWithdrawals[1]) + if err != nil { + t.Fatalf("withdrawal HTR: %v", err) + } + if !bytes.Equal(direct.Leaf, leaf[:]) { + t.Fatalf("leaf mismatch") + } + if ok, err := treeproof.VerifyProof(stateRoot, direct); err != nil || !ok { + t.Fatalf("verify expected withdrawal proof: ok=%v err=%v", ok, err) + } + if len(proofHashes) != len(direct.Hashes) { + t.Fatalf("helper proof length %d != direct %d", len(proofHashes), len(direct.Hashes)) + } + for i := range proofHashes { + if !bytes.Equal(proofHashes[i], direct.Hashes[i]) { + t.Fatalf("proof hash[%d] mismatch", i) + } + } + + // Out-of-bounds indices must error. + if _, err := state.ProveExpectedWithdrawal(2); err == nil { + t.Fatalf("expected out-of-bounds error") + } +} + +func TestStateRootProofProgressive(t *testing.T) { + state := minimalBeaconState() + // Slot far enough that state_roots[slot % 8192] is still "recent". + state.Slot = 100 + // Plant a distinctive root at index 10. + var planted [32]byte + for i := range planted { + planted[i] = byte(i + 42) + } + state.StateRoots[10] = planted + + tree, err := generic.SSZ.GetTree(state) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + + // Prove state_roots[10] via the helper (progressive field gindex + vector). + proofHashes, err := state.StateRootProof(10) + if err != nil { + t.Fatalf("StateRootProof: %v", err) + } + + gid := generic.GetGeneralizedIndexForVectorElement( + GetGeneralizedIndexForStateRoots(), + generic.BeaconStateStateRootsMaxLength, + 10, + ) + direct, err := tree.Prove(int(gid)) + if err != nil { + t.Fatalf("direct Prove: %v", err) + } + if !bytes.Equal(direct.Leaf, planted[:]) { + t.Fatalf("leaf mismatch: got %x want %x", direct.Leaf, planted) + } + if ok, err := treeproof.VerifyProof(tree.Hash(), direct); err != nil || !ok { + t.Fatalf("verify state root: ok=%v err=%v", ok, err) + } + if len(proofHashes) != len(direct.Hashes) { + t.Fatalf("helper proof length %d != direct %d", len(proofHashes), len(direct.Hashes)) + } + for i := range proofHashes { + if !bytes.Equal(proofHashes[i], direct.Hashes[i]) { + t.Fatalf("proof hash[%d] mismatch", i) + } + } + + // A slot that rolled out of the ring must error (use historical_summaries). + state.Slot = generic.SlotsPerHistoricalRoot + 100 + if _, err := state.StateRootProof(0); err == nil { + t.Fatalf("expected historical-slot error") + } +} + +func TestHistoricalSummaryStateRootProof(t *testing.T) { + state := minimalBeaconState() + // Era-aligned state: its state_roots ring covers the full previous era. + state.Slot = generic.SlotsPerHistoricalRoot + var planted [32]byte + for i := range planted { + planted[i] = byte(i + 77) + } + state.StateRoots[7] = planted + + proofHashes, err := state.HistoricalSummaryStateRootProof(7) + if err != nil { + t.Fatalf("HistoricalSummaryStateRootProof: %v", err) + } + + // Direct proof against the HistoricalSummaryLists tree (gid 3 → state_roots). + hsls := generic.HistoricalSummaryLists{ + BlockRoots: state.BlockRoots, + StateRoots: state.StateRoots, + } + tree, err := generic.SSZ.GetTree(&hsls) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + gid := uint64(1) + gid = gid*2 + 1 + gid = gid * generic.SlotsPerHistoricalRoot + gid = gid + 7 + direct, err := tree.Prove(int(gid)) + if err != nil { + t.Fatalf("direct Prove: %v", err) + } + if !bytes.Equal(direct.Leaf, planted[:]) { + t.Fatalf("leaf mismatch") + } + if ok, err := treeproof.VerifyProof(tree.Hash(), direct); err != nil || !ok { + t.Fatalf("verify historical summary state root: ok=%v err=%v", ok, err) + } + if len(proofHashes) != len(direct.Hashes) { + t.Fatalf("helper proof length %d != direct %d", len(proofHashes), len(direct.Hashes)) + } + for i := range proofHashes { + if !bytes.Equal(proofHashes[i], direct.Hashes[i]) { + t.Fatalf("proof hash[%d] mismatch", i) + } + } + + // Non-aligned states must error. + state.Slot = generic.SlotsPerHistoricalRoot + 1 + if _, err := state.HistoricalSummaryStateRootProof(7); err == nil { + t.Fatalf("expected non-aligned state error") + } +} diff --git a/shared/types/eth2/fork/gloas/gloas_ssz_test.go b/shared/types/eth2/fork/gloas/gloas_ssz_test.go new file mode 100644 index 000000000..78aea8ae0 --- /dev/null +++ b/shared/types/eth2/fork/gloas/gloas_ssz_test.go @@ -0,0 +1,194 @@ +package gloas + +import ( + "bytes" + "reflect" + "testing" + + "github.com/rocket-pool/smartnode/shared/types/eth2/generic" +) + +// minimalBeaconState returns a Gloas BeaconState with required fixed-size +// vectors populated so SSZ marshal/HTR succeed. +func minimalBeaconState() *BeaconState { + state := &BeaconState{ + GenesisTime: 1, + GenesisValidatorsRoot: make([]byte, 32), + Slot: 42, + Fork: &generic.Fork{ + PreviousVersion: make([]byte, 4), + CurrentVersion: make([]byte, 4), + Epoch: 0, + }, + LatestBlockHeader: &generic.BeaconBlockHeader{ + ParentRoot: make([]byte, 32), + StateRoot: make([]byte, 32), + BodyRoot: make([]byte, 32), + }, + Eth1Data: &generic.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + }, + RandaoMixes: make([][]byte, 65536), + Slashings: make([]uint64, 8192), + JustificationBits: [1]byte{0}, + PreviousJustifiedCheckpoint: &generic.Checkpoint{ + Root: make([]byte, 32), + }, + CurrentJustifiedCheckpoint: &generic.Checkpoint{ + Root: make([]byte, 32), + }, + FinalizedCheckpoint: &generic.Checkpoint{ + Root: make([]byte, 32), + }, + CurrentSyncCommittee: &generic.SyncCommittee{ + PubKeys: make([][]byte, 512), + }, + NextSyncCommittee: &generic.SyncCommittee{ + PubKeys: make([][]byte, 512), + }, + ProposerLookahead: make([]uint64, 64), + ExecutionPayloadAvailability: make([]byte, 1024), + LatestExecutionPayloadBid: &ExecutionPayloadBid{ + BlobKzgCommitments: nil, + }, + } + for i := range state.RandaoMixes { + state.RandaoMixes[i] = make([]byte, 32) + } + for i := range state.CurrentSyncCommittee.PubKeys { + state.CurrentSyncCommittee.PubKeys[i] = make([]byte, 48) + } + for i := range state.NextSyncCommittee.PubKeys { + state.NextSyncCommittee.PubKeys[i] = make([]byte, 48) + } + for i := range state.BuilderPendingPayments { + state.BuilderPendingPayments[i] = &BuilderPendingPayment{ + Withdrawal: &BuilderPendingWithdrawal{}, + } + } + return state +} + +func TestBeaconStateRoundTrip(t *testing.T) { + state := minimalBeaconState() + state.Validators = []*generic.Validator{ + { + Pubkey: make([]byte, 48), + WithdrawalCredentials: make([]byte, 32), + }, + } + state.Balances = []uint64{32_000_000_000} + state.PayloadExpectedWithdrawals = []*generic.Withdrawal{ + { + Index: 1, + ValidatorIndex: 0, + Address: [20]byte{}, + Amount: 1_000_000_000, + }, + } + + encoded, err := generic.SSZ.MarshalSSZ(state) + if err != nil { + t.Fatalf("MarshalSSZ: %v", err) + } + + decoded := &BeaconState{} + if err := generic.SSZ.UnmarshalSSZ(decoded, encoded); err != nil { + t.Fatalf("UnmarshalSSZ: %v", err) + } + + if decoded.Slot != state.Slot { + t.Fatalf("slot: got %d want %d", decoded.Slot, state.Slot) + } + if len(decoded.Validators) != 1 { + t.Fatalf("validators len: got %d want 1", len(decoded.Validators)) + } + if len(decoded.PayloadExpectedWithdrawals) != 1 { + t.Fatalf("payload_expected_withdrawals len: got %d want 1", len(decoded.PayloadExpectedWithdrawals)) + } + if decoded.PayloadExpectedWithdrawals[0].Amount != 1_000_000_000 { + t.Fatalf("withdrawal amount: got %d", decoded.PayloadExpectedWithdrawals[0].Amount) + } + + origRoot, err := generic.SSZ.HashTreeRoot(state) + if err != nil { + t.Fatalf("HashTreeRoot original: %v", err) + } + decodedRoot, err := generic.SSZ.HashTreeRoot(decoded) + if err != nil { + t.Fatalf("HashTreeRoot decoded: %v", err) + } + if !bytes.Equal(origRoot[:], decodedRoot[:]) { + t.Fatalf("HTR mismatch after round-trip:\n orig=%x\n dec =%x", origRoot, decodedRoot) + } +} + +func TestSignedBeaconBlockRoundTrip(t *testing.T) { + block := &SignedBeaconBlock{ + Block: &BeaconBlock{ + Slot: 7, + ParentRoot: [32]byte{1}, + StateRoot: [32]byte{2}, + Body: &BeaconBlockBody{ + RandaoReveal: make([]byte, 96), + Eth1Data: &generic.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + }, + SyncAggregate: &generic.SyncAggregate{ + SyncCommiteeBits: make([]byte, 64), + }, + SignedExecutionPayloadBid: &SignedExecutionPayloadBid{ + Message: &ExecutionPayloadBid{}, + }, + ParentExecutionRequests: &ExecutionRequests{}, + }, + }, + Signature: make([]byte, 96), + } + + encoded, err := generic.SSZ.MarshalSSZ(block) + if err != nil { + t.Fatalf("MarshalSSZ: %v", err) + } + + decoded := &SignedBeaconBlock{} + if err := generic.SSZ.UnmarshalSSZ(decoded, encoded); err != nil { + t.Fatalf("UnmarshalSSZ: %v", err) + } + + if decoded.Block.Slot != block.Block.Slot { + t.Fatalf("slot: got %d want %d", decoded.Block.Slot, block.Block.Slot) + } + + origRoot, err := generic.SSZ.HashTreeRoot(block) + if err != nil { + t.Fatalf("HashTreeRoot original: %v", err) + } + decodedRoot, err := generic.SSZ.HashTreeRoot(decoded) + if err != nil { + t.Fatalf("HashTreeRoot decoded: %v", err) + } + if !bytes.Equal(origRoot[:], decodedRoot[:]) { + t.Fatalf("HTR mismatch after round-trip:\n orig=%x\n dec =%x", origRoot, decodedRoot) + } +} + +func TestProgressiveTypesValidate(t *testing.T) { + // Ensure dynamic-ssz accepts progressive container/list annotations on Gloas types. + for _, typ := range []any{ + (*BeaconState)(nil), + (*BeaconBlockBody)(nil), + (*Attestation)(nil), + (*ExecutionPayloadBid)(nil), + (*ExecutionRequests)(nil), + (*IndexedAttestation)(nil), + (*PayloadAttestation)(nil), + } { + rt := reflect.TypeOf(typ).Elem() + if err := generic.SSZ.ValidateType(rt); err != nil { + t.Fatalf("ValidateType(%s): %v", rt, err) + } + } +} diff --git a/shared/types/eth2/fork/gloas/state_gloas.go b/shared/types/eth2/fork/gloas/state_gloas.go new file mode 100644 index 000000000..d79ab4070 --- /dev/null +++ b/shared/types/eth2/fork/gloas/state_gloas.go @@ -0,0 +1,455 @@ +package gloas + +import ( + "bytes" + "errors" + "fmt" + + "github.com/rocket-pool/smartnode/shared/types/eth2/generic" +) + +// Gloas BeaconState field ssz-indices (EIP-7688 ProgressiveContainer). +// Must stay aligned with the BeaconState struct tags. +const ( + beaconStateSlotFieldIndex = generic.BeaconStateSlotIndex // 2 + beaconStateBlockRootsFieldIndex = generic.BeaconStateBlockRootsFieldIndex // 5 + beaconStateStateRootsFieldIndex = generic.BeaconStateStateRootsFieldIndex // 6 + beaconStateValidatorsFieldIndex = generic.BeaconStateValidatorsIndex // 11 + beaconStateHistoricalSummariesFieldIndex = generic.BeaconStateHistoricalSummariesFieldIndex // 27 + // New in Gloas (EIP-7732): payload_expected_withdrawals commits to the + // withdrawals of the execution payload bid on at this slot. + beaconStatePayloadExpectedWithdrawalsFieldIndex = 44 +) + +// New in Gloas (EIP-7732). Immutable container (not ProgressiveContainer). +type Builder struct { + Pubkey []byte `json:"pubkey" ssz-size:"48"` + Version uint8 `json:"version"` + ExecutionAddress [20]byte `json:"execution_address" ssz-size:"20"` + Balance uint64 `json:"balance"` + DepositEpoch uint64 `json:"deposit_epoch"` + WithdrawableEpoch uint64 `json:"withdrawable_epoch"` +} + +// New in Gloas (EIP-7732). Immutable container (not ProgressiveContainer). +type BuilderPendingWithdrawal struct { + FeeRecipient [20]byte `json:"fee_recipient" ssz-size:"20"` + Amount uint64 `json:"amount"` + BuilderIndex uint64 `json:"builder_index"` +} + +// New in Gloas (EIP-7732). Immutable container (not ProgressiveContainer). +type BuilderPendingPayment struct { + Weight uint64 `json:"weight"` + Withdrawal *BuilderPendingWithdrawal `json:"withdrawal"` + ProposerIndex uint64 `json:"proposer_index"` +} + +// Adapted from the Fulu BeaconState to the Gloas spec +// (https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#beaconstate): +// - Removed LatestExecutionPayloadHeader, replaced (in place) by LatestBlockHash (EIP-7732) +// - Added the builder/ePBS fields after ProposerLookahead (EIP-7732) +// - EIP-7688: ProgressiveContainer + ProgressiveList on evolving fields +type BeaconState struct { + GenesisTime uint64 `json:"genesis_time" ssz-index:"0"` + GenesisValidatorsRoot []byte `json:"genesis_validators_root" ssz-size:"32" ssz-index:"1"` + Slot uint64 `json:"slot" ssz-index:"2"` + Fork *generic.Fork `json:"fork" ssz-index:"3"` + LatestBlockHeader *generic.BeaconBlockHeader `json:"latest_block_header" ssz-index:"4"` + BlockRoots [8192][32]byte `json:"block_roots" ssz-size:"8192,32" ssz-index:"5"` + StateRoots [8192][32]byte `json:"state_roots" ssz-size:"8192,32" ssz-index:"6"` + HistoricalRoots [][]byte `json:"historical_roots" ssz-max:"16777216" ssz-size:"?,32" ssz-index:"7"` + Eth1Data *generic.Eth1Data `json:"eth1_data" ssz-index:"8"` + Eth1DataVotes []*generic.Eth1Data `json:"eth1_data_votes" ssz-max:"2048" ssz-index:"9"` + Eth1DepositIndex uint64 `json:"eth1_deposit_index" ssz-index:"10"` + Validators []*generic.Validator `json:"validators" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"11"` + Balances []uint64 `json:"balances" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"12"` + RandaoMixes [][]byte `json:"randao_mixes" ssz-size:"65536,32" ssz-index:"13"` + Slashings []uint64 `json:"slashings" ssz-size:"8192" ssz-index:"14"` + PreviousEpochParticipation []byte `json:"previous_epoch_participation" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"15"` + CurrentEpochParticipation []byte `json:"current_epoch_participation" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"16"` + JustificationBits [1]byte `json:"justification_bits" ssz-size:"1" ssz-index:"17"` + PreviousJustifiedCheckpoint *generic.Checkpoint `json:"previous_justified_checkpoint" ssz-index:"18"` + CurrentJustifiedCheckpoint *generic.Checkpoint `json:"current_justified_checkpoint" ssz-index:"19"` + FinalizedCheckpoint *generic.Checkpoint `json:"finalized_checkpoint" ssz-index:"20"` + InactivityScores []uint64 `json:"inactivity_scores" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"21"` + CurrentSyncCommittee *generic.SyncCommittee `json:"current_sync_committee" ssz-index:"22"` + NextSyncCommittee *generic.SyncCommittee `json:"next_sync_committee" ssz-index:"23"` + LatestBlockHash [32]byte `json:"latest_block_hash" ssz-size:"32" ssz-index:"24"` // New in Gloas (EIP-7732) + NextWithdrawalIndex uint64 `json:"next_withdrawal_index" ssz-index:"25"` + NextWithdrawalValidatorIndex uint64 `json:"next_withdrawal_validator_index" ssz-index:"26"` + HistoricalSummaries []*generic.HistoricalSummary `json:"historical_summaries" ssz-max:"16777216" ssz-index:"27"` + + // New in Electra + DepositRequestsStartIndex uint64 `json:"deposit_requests_start_index" ssz-index:"28"` + DepositBalanceToConsume uint64 `json:"deposit_balance_to_consume" ssz-index:"29"` + ExitBalanceToConsume uint64 `json:"exit_balance_to_consume" ssz-index:"30"` + EarliestExitEpoch uint64 `json:"earliest_exit_epoch" ssz-index:"31"` + ConsolidationBalanceToConsume uint64 `json:"consolidation_balance_to_consume" ssz-index:"32"` + EarliestConsolidationEpoch uint64 `json:"earliest_consolidation_epoch" ssz-index:"33"` + PendingDeposits []*generic.PendingDeposit `json:"pending_deposits,omitempty" ssz-type:"progressive-list" ssz-max:"134217728" ssz-index:"34"` + PendingPartialWithdrawals []*generic.PendingPartialWithdrawal `json:"pending_partial_withdrawals,omitempty" ssz-type:"progressive-list" ssz-max:"134217728" ssz-index:"35"` + PendingConsolidations []*generic.PendingConsolidation `json:"pending_consolidations,omitempty" ssz-type:"progressive-list" ssz-max:"262144" ssz-index:"36"` + + // New in Fulu + ProposerLookahead []uint64 `json:"proposer_lookahead,omitempty" ssz-size:"64" ssz-index:"37"` + + // New in Gloas (EIP-7732) + Builders []*Builder `json:"builders,omitempty" ssz-type:"progressive-list" ssz-max:"1099511627776" ssz-index:"38"` + NextWithdrawalBuilderIndex uint64 `json:"next_withdrawal_builder_index" ssz-index:"39"` + ExecutionPayloadAvailability []byte `json:"execution_payload_availability" ssz-size:"1024" ssz-index:"40"` // Bitvector[SLOTS_PER_HISTORICAL_ROOT] + BuilderPendingPayments [64]*BuilderPendingPayment `json:"builder_pending_payments" ssz-size:"64" ssz-index:"41"` // Vector[BuilderPendingPayment, 2 * SLOTS_PER_EPOCH] + BuilderPendingWithdrawals []*BuilderPendingWithdrawal `json:"builder_pending_withdrawals,omitempty" ssz-type:"progressive-list" ssz-max:"134217728" ssz-index:"42"` + LatestExecutionPayloadBid *ExecutionPayloadBid `json:"latest_execution_payload_bid" ssz-index:"43"` + PayloadExpectedWithdrawals []*generic.Withdrawal `json:"payload_expected_withdrawals,omitempty" ssz-type:"progressive-list" ssz-max:"16" ssz-index:"44"` + // Vector[Vector[ValidatorIndex, PTC_SIZE], (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH] + // = 96 slots x 512 validator indices. + PtcWindow [96][512]uint64 `json:"ptc_window" ssz-size:"96,512" ssz-index:"45"` +} + +// GetGeneralizedIndexForValidators returns the gindex of the validators field +// root inside the Gloas ProgressiveContainer BeaconState. +func GetGeneralizedIndexForValidators() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStateValidatorsFieldIndex) +} + +// GetGeneralizedIndexForSlot returns the gindex of the slot field inside the +// Gloas ProgressiveContainer BeaconState. +func GetGeneralizedIndexForSlot() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStateSlotFieldIndex) +} + +// GetGeneralizedIndexForBlockRoots returns the gindex of the block_roots field +// root inside the Gloas ProgressiveContainer BeaconState. +func GetGeneralizedIndexForBlockRoots() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStateBlockRootsFieldIndex) +} + +// GetGeneralizedIndexForHistoricalSummaries returns the gindex of the +// historical_summaries field root inside the Gloas ProgressiveContainer BeaconState. +// historical_summaries remains a normal List (not ProgressiveList) per EIP-7688. +func GetGeneralizedIndexForHistoricalSummaries() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStateHistoricalSummariesFieldIndex) +} + +// GetGeneralizedIndexForStateRoots returns the gindex of the state_roots field +// root inside the progressive container. +func GetGeneralizedIndexForStateRoots() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStateStateRootsFieldIndex) +} + +// GetGeneralizedIndexForPayloadExpectedWithdrawals returns the gindex of the +// payload_expected_withdrawals field root inside progressive container +func GetGeneralizedIndexForPayloadExpectedWithdrawals() uint64 { + return generic.ProgressiveContainerFieldGindex(beaconStatePayloadExpectedWithdrawalsFieldIndex) +} + +// GetGeneralizedIndexForExpectedWithdrawal returns the gindex of +// payload_expected_withdrawals[index] +// (ProgressiveContainer field + ProgressiveList element). +func GetGeneralizedIndexForExpectedWithdrawal(index uint64) uint64 { + return generic.GetGeneralizedIndexForProgressiveListElement( + GetGeneralizedIndexForPayloadExpectedWithdrawals(), + index, + ) +} + +// GetGeneralizedIndexForValidator returns the gindex of validators[index] in a +// Gloas BeaconState (ProgressiveContainer field + ProgressiveList element). +func GetGeneralizedIndexForValidator(validatorIndex uint64) uint64 { + return generic.GetGeneralizedIndexForProgressiveListElement( + GetGeneralizedIndexForValidators(), + validatorIndex, + ) +} + +// ValidatorAndSlotProof produces both the validator proof and the slot proof +// for the state's current slot, using EIP-7688 progressive g-indices. +func (state *BeaconState) ValidatorAndSlotProof(validatorIndex uint64) ([][]byte, [][]byte, error) { + + if validatorIndex >= uint64(len(state.Validators)) { + return nil, nil, errors.New("validator index out of bounds") + } + + stateTree, err := generic.SSZ.GetTree(state) + if err != nil { + return nil, nil, fmt.Errorf("could not get state tree: %w", err) + } + + validatorGid := GetGeneralizedIndexForValidator(validatorIndex) + validatorStateProof, err := stateTree.Prove(int(validatorGid)) + if err != nil { + return nil, nil, fmt.Errorf("could not get proof for validator: %w", err) + } + + // Sanity check that the proof leaf matches the expected validator + validatorHashTreeRoot, err := generic.SSZ.HashTreeRoot(state.Validators[validatorIndex]) + if err != nil { + return nil, nil, fmt.Errorf("could not get hash tree root for validator: %w", err) + } + if !bytes.Equal(validatorStateProof.Leaf, validatorHashTreeRoot[:]) { + return nil, nil, fmt.Errorf("proof leaf does not match expected validator") + } + + slotStateProof, err := stateTree.Prove(int(GetGeneralizedIndexForSlot())) + if err != nil { + return nil, nil, fmt.Errorf("could not get proof for slot: %w", err) + } + + // Drop the state tree before doing more work so the GC can reclaim it. + stateTree = nil + + bhTree, err := generic.SSZ.GetTree(state.LatestBlockHeader) + if err != nil { + return nil, nil, fmt.Errorf("could not get block header tree: %w", err) + } + blockHeaderProof, err := bhTree.Prove(int(generic.BeaconBlockHeaderStateRootGeneralizedIndex)) + if err != nil { + return nil, nil, fmt.Errorf("could not get proof for block header: %w", err) + } + + validatorProof := make([][]byte, 0, len(validatorStateProof.Hashes)+len(blockHeaderProof.Hashes)) + validatorProof = append(validatorProof, validatorStateProof.Hashes...) + validatorProof = append(validatorProof, blockHeaderProof.Hashes...) + + slotProof := make([][]byte, 0, len(slotStateProof.Hashes)+len(blockHeaderProof.Hashes)) + slotProof = append(slotProof, slotStateProof.Hashes...) + slotProof = append(slotProof, blockHeaderProof.Hashes...) + + return validatorProof, slotProof, nil +} + +func (state *BeaconState) blockHeaderToStateProof(blockHeader *generic.BeaconBlockHeader) ([][]byte, error) { + generalizedIndex := generic.BeaconBlockHeaderStateRootGeneralizedIndex + root, err := generic.SSZ.GetTree(blockHeader) + if err != nil { + return nil, fmt.Errorf("could not get block header tree: %w", err) + } + blockHeaderProof, err := root.Prove(int(generalizedIndex)) + if err != nil { + return nil, fmt.Errorf("could not get proof for block header: %w", err) + } + return blockHeaderProof.Hashes, nil +} + +func (state *BeaconState) HistoricalSummaryProof(slot uint64, capellaOffset uint64) ([][]byte, error) { + isHistorical := slot+generic.SlotsPerHistoricalRoot <= state.Slot + if !isHistorical { + return nil, fmt.Errorf("slot %d is less than %d slots in the past from the state at slot %d, you must build a proof from the block_roots field instead", slot, generic.SlotsPerHistoricalRoot, state.Slot) + } + tree, err := generic.SSZ.GetTree(state) + if err != nil { + return nil, fmt.Errorf("could not get state tree: %w", err) + } + + // ProgressiveContainer field → historical_summaries (still a fixed-capacity List). + arrayIndex := (slot / generic.SlotsPerHistoricalRoot) - capellaOffset + gid := generic.GetGeneralizedIndexForListElement( + GetGeneralizedIndexForHistoricalSummaries(), + generic.BeaconStateHistoricalSummariesMaxLength, + arrayIndex, + ) + + proof, err := tree.Prove(int(gid)) + if err != nil { + return nil, fmt.Errorf("could not get proof for historical block root: %w", err) + } + + // The EL proves against BeaconBlockHeader root, so we need to merge the state proof with that. + blockHeaderProof, err := state.blockHeaderToStateProof(state.LatestBlockHeader) + if err != nil { + return nil, fmt.Errorf("could not get block header proof: %w", err) + } + return append(proof.Hashes, blockHeaderProof...), nil +} + +func (state *BeaconState) HistoricalSummaryBlockRootProof(slot int) ([][]byte, error) { + // If the state isn't aligned at the end of an 8192 slot era, throw an error + if state.Slot%generic.SlotsPerHistoricalRoot != 0 { + return nil, fmt.Errorf("state is not aligned at the end of an 8192 slot era") + } + + hsls := generic.HistoricalSummaryLists{ + BlockRoots: state.BlockRoots, + StateRoots: state.StateRoots, + } + + idx := slot % int(generic.SlotsPerHistoricalRoot) + tree, err := generic.SSZ.GetTree(&hsls) + if err != nil { + return nil, fmt.Errorf("could not get historical summary lists tree: %w", err) + } + + gid := uint64(1) + gid = gid * 2 // Now at block_roots + gid = gid * generic.SlotsPerHistoricalRoot // Now at the first block_root + gid = gid + uint64(idx) // Now at the correct block_root + + proof, err := tree.Prove(int(gid)) + if err != nil { + return nil, fmt.Errorf("could not get proof for historical summary: %w", err) + } + + return proof.Hashes, nil +} + +func (state *BeaconState) BlockRootProof(slot uint64) ([][]byte, error) { + isHistorical := slot+generic.SlotsPerHistoricalRoot <= state.Slot + if isHistorical { + return nil, fmt.Errorf("slot %d is more than %d slots in the past from the state at slot %d, you must build a proof from the historical_summaries instead", slot, generic.SlotsPerHistoricalRoot, state.Slot) + } + + tree, err := generic.SSZ.GetTree(state) + if err != nil { + return nil, fmt.Errorf("could not get state tree: %w", err) + } + + // ProgressiveContainer field → block_roots Vector[Root, SLOTS_PER_HISTORICAL_ROOT]. + gid := generic.GetGeneralizedIndexForVectorElement( + GetGeneralizedIndexForBlockRoots(), + generic.BeaconStateBlockRootsMaxLength, + slot%generic.SlotsPerHistoricalRoot, + ) + + proof, err := tree.Prove(int(gid)) + if err != nil { + return nil, fmt.Errorf("could not get proof for block root: %w", err) + } + + return proof.Hashes, nil +} + +// StateRootProof proves state_roots[slot % SLOTS_PER_HISTORICAL_ROOT] against +// this state's root. It is the state_roots counterpart of BlockRootProof and is +// used to anchor the post-state root of a recent slot inside a later +// (finalized) state. Used for Gloas withdrawal proofs. +func (state *BeaconState) StateRootProof(slot uint64) ([][]byte, error) { + isHistorical := slot+generic.SlotsPerHistoricalRoot <= state.Slot + if isHistorical { + return nil, fmt.Errorf("slot %d is more than %d slots in the past from the state at slot %d, you must build a proof from the historical_summaries instead", slot, generic.SlotsPerHistoricalRoot, state.Slot) + } + + tree, err := generic.SSZ.GetTree(state) + if err != nil { + return nil, fmt.Errorf("could not get state tree: %w", err) + } + + // ProgressiveContainer field → state_roots Vector[Root, SLOTS_PER_HISTORICAL_ROOT]. + gid := generic.GetGeneralizedIndexForVectorElement( + GetGeneralizedIndexForStateRoots(), + generic.BeaconStateStateRootsMaxLength, + slot%generic.SlotsPerHistoricalRoot, + ) + + proof, err := tree.Prove(int(gid)) + if err != nil { + return nil, fmt.Errorf("could not get proof for state root: %w", err) + } + + return proof.Hashes, nil +} + +// HistoricalSummaryStateRootProof proves state_roots[slot] against the +// state_summary_root of the HistoricalSummary for the slot's 8192-slot era. It +// is the state_roots counterpart of HistoricalSummaryBlockRootProof. The state +// must be aligned at the end of the era following the slot. +func (state *BeaconState) HistoricalSummaryStateRootProof(slot int) ([][]byte, error) { + // If the state isn't aligned at the end of an 8192 slot era, throw an error + if state.Slot%generic.SlotsPerHistoricalRoot != 0 { + return nil, fmt.Errorf("state is not aligned at the end of an 8192 slot era") + } + + hsls := generic.HistoricalSummaryLists{ + BlockRoots: state.BlockRoots, + StateRoots: state.StateRoots, + } + + idx := slot % int(generic.SlotsPerHistoricalRoot) + tree, err := generic.SSZ.GetTree(&hsls) + if err != nil { + return nil, fmt.Errorf("could not get historical summary lists tree: %w", err) + } + + gid := uint64(1) + gid = gid*2 + 1 // Now at state_roots + gid = gid * generic.SlotsPerHistoricalRoot // Now at the first state_root + gid = gid + uint64(idx) // Now at the correct state_root + + proof, err := tree.Prove(int(gid)) + if err != nil { + return nil, fmt.Errorf("could not get proof for historical summary: %w", err) + } + + return proof.Hashes, nil +} + +// ProveExpectedWithdrawal proves payload_expected_withdrawals[index] against +// the state root. In Gloas the execution payload is no longer part +// of the beacon block, so withdrawals cannot be proven against a block root. +// Instead, process_withdrawals commits the withdrawals that the payload for +// this slot must contain to the state's payload_expected_withdrawals field, and +// that list is what the withdrawal is proven against. +// +// The proof ends at the state root; anchoring the state root to a later +// finalized state (via StateRootProof for recent slots, or +// HistoricalSummaryStateRootProof + a historical summary proof for older ones) +// is left to the caller. +func (state *BeaconState) ProveExpectedWithdrawal(index uint64) ([][]byte, error) { + if index >= uint64(len(state.PayloadExpectedWithdrawals)) { + return nil, fmt.Errorf("withdrawal index %d out of bounds: state at slot %d has %d expected withdrawals", index, state.Slot, len(state.PayloadExpectedWithdrawals)) + } + + stateTree, err := generic.SSZ.GetTree(state) + if err != nil { + return nil, fmt.Errorf("could not get state tree: %w", err) + } + + proof, err := stateTree.Prove(int(GetGeneralizedIndexForExpectedWithdrawal(index))) + if err != nil { + return nil, fmt.Errorf("could not get proof for expected withdrawal: %w", err) + } + + // Sanity check that the proof leaf matches the expected withdrawal + withdrawalHashTreeRoot, err := generic.SSZ.HashTreeRoot(state.PayloadExpectedWithdrawals[index]) + if err != nil { + return nil, fmt.Errorf("could not get hash tree root for expected withdrawal: %w", err) + } + if !bytes.Equal(proof.Leaf, withdrawalHashTreeRoot[:]) { + return nil, fmt.Errorf("proof leaf does not match expected withdrawal") + } + + return proof.Hashes, nil +} + +func (state *BeaconState) BlockHeaderProof() ([][]byte, error) { + // Construct block header with state root + stateRoot, err := generic.SSZ.HashTreeRoot(state) + if err != nil { + return nil, fmt.Errorf("could not get state root: %w", err) + } + latestBlockHeader := state.LatestBlockHeader + blockHeader := *latestBlockHeader + blockHeader.StateRoot = stateRoot[:] + blockHeaderTree, err := generic.SSZ.GetTree(&blockHeader) + if err != nil { + return nil, fmt.Errorf("could not get block header tree: %w", err) + } + blockHeaderProofResult, err := blockHeaderTree.Prove(int(generic.BeaconBlockHeaderStateRootGeneralizedIndex)) + if err != nil { + return nil, fmt.Errorf("could not get block header proof: %w", err) + } + return blockHeaderProofResult.Hashes, nil + +} + +func (state *BeaconState) GetValidators() []*generic.Validator { + return state.Validators +} + +func (state *BeaconState) GetSlot() uint64 { + return state.Slot +} + +func (state *BeaconState) GetPreviousEpochParticipation() []byte { + return state.PreviousEpochParticipation +} diff --git a/shared/types/eth2/generic/gindex.go b/shared/types/eth2/generic/gindex.go new file mode 100644 index 000000000..20d1e98ec --- /dev/null +++ b/shared/types/eth2/generic/gindex.go @@ -0,0 +1,62 @@ +package generic + +import ( + "github.com/rocket-pool/smartnode/shared/math" +) + +// Pre-Gloas SSZ generalized-index helpers. +// +// Use these for Deneb / Electra / Fulu where it still merkleizes +// BeaconState / lists with pre-Gloas SSZ Container and List[T, N] trees. +// +// Gloas (EIP-7688) switched evolving containers/lists to ProgressiveContainer / +// ProgressiveList. For those types use the helpers in progressive.go instead: +// ProgressiveContainerFieldGindex, ProgressiveListElementGindex, etc. +// +// Nested Vector and fixed-capacity List navigation under either style of parent +// still uses GetGeneralizedIndexForVectorElement / GetGeneralizedIndexForListElement. + +// ContainerFieldGindex returns the generalized index of field `fieldIndex` +// inside a standard SSZ Container that has `fieldCount` fields. +// +// Fields are left-aligned in a binary tree of width nextPowerOfTwo(fieldCount), +// so the gindex is nextPowerOfTwo(fieldCount) + fieldIndex (root = 1). +// +// Pre-Gloas only. Progressive containers use ProgressiveContainerFieldGindex. +func ContainerFieldGindex(fieldCount, fieldIndex uint64) uint64 { + return math.GetPowerOfTwoCeil(fieldCount) + fieldIndex +} + +// GetGeneralizedIndexForValidator returns the gindex of validators[index] when +// validators is a fixed-capacity SSZ List[Validator, VALIDATOR_REGISTRY_LIMIT] +// (capacity 2^40) sitting at validatorsArrayIndex in the parent tree. +// +// Pre-Gloas only. Gloas validators are a ProgressiveList; use +// GetGeneralizedIndexForProgressiveListElement (or gloas.GetGeneralizedIndexForValidator). +func GetGeneralizedIndexForValidator(index uint64, validatorsArrayIndex uint64) uint64 { + // List root mixes in length: left = data tree, right = length. + // Composite list elements are one leaf each; capacity is power-of-two max length. + return GetGeneralizedIndexForListElement(validatorsArrayIndex, beaconStateValidatorsMaxLength, index) +} + +// GetGeneralizedIndexForListElement returns the gindex of an element inside a +// fixed-capacity SSZ List[T, N] (with length mixin) that sits at listRootGindex. +// capacity must be a power of two (typically the list's N). +// +// Applies under both classic Containers and ProgressiveContainers once you have +// the list field's root gindex (historical_summaries stays a normal List in Gloas). +func GetGeneralizedIndexForListElement(listRootGindex uint64, capacity uint64, elementIndex uint64) uint64 { + // List root: left = data tree, right = length. Data leaves start at + // listRoot * 2 * capacity + elementIndex. + return listRootGindex*2*capacity + elementIndex +} + +// GetGeneralizedIndexForVectorElement returns the gindex of an element inside a +// fixed-length SSZ Vector[T, N] that sits at vectorRootGindex. length must be a +// power of two. +// +// Applies under both classic Containers and ProgressiveContainers once you have +// the vector field's root gindex (e.g. block_roots). +func GetGeneralizedIndexForVectorElement(vectorRootGindex uint64, length uint64, elementIndex uint64) uint64 { + return vectorRootGindex*length + elementIndex +} diff --git a/shared/types/eth2/generic/gindex_test.go b/shared/types/eth2/generic/gindex_test.go new file mode 100644 index 000000000..6ef05b26d --- /dev/null +++ b/shared/types/eth2/generic/gindex_test.go @@ -0,0 +1,44 @@ +package generic + +import "testing" + +func TestContainerFieldGindex(t *testing.T) { + // Pre-Gloas Deneb-style: 28 fields → width 32; validators at index 11 → 43 + if got := ContainerFieldGindex(28, BeaconStateValidatorsIndex); got != 43 { + t.Fatalf("validators (28 fields): got %d want 43", got) + } + // Slot at index 2 → 34 + if got := ContainerFieldGindex(28, BeaconStateSlotIndex); got != 34 { + t.Fatalf("slot (28 fields): got %d want 34", got) + } + // Fulu-style: 37+ fields → width 64; validators → 75 + if got := ContainerFieldGindex(38, BeaconStateValidatorsIndex); got != 75 { + t.Fatalf("validators (38 fields): got %d want 75", got) + } +} + +func TestGetGeneralizedIndexForValidatorClassic(t *testing.T) { + // validators field at classic gindex 43 (deneb), index 0 + // = 43 * 2 * 2^40 + 0 + validatorsField := ContainerFieldGindex(28, BeaconStateValidatorsIndex) + got := GetGeneralizedIndexForValidator(0, validatorsField) + want := validatorsField * 2 * beaconStateValidatorsMaxLength + if got != want { + t.Fatalf("validator 0: got %d want %d", got, want) + } + got1 := GetGeneralizedIndexForValidator(1, validatorsField) + if got1 != want+1 { + t.Fatalf("validator 1: got %d want %d", got1, want+1) + } +} + +func TestGetGeneralizedIndexForVectorAndList(t *testing.T) { + // Vector of length 8 at root 1: element 3 at 1*8+3 = 11 + if got := GetGeneralizedIndexForVectorElement(1, 8, 3); got != 11 { + t.Fatalf("vector: got %d want 11", got) + } + // List capacity 16 at root 1: element 3 at 1*2*16+3 = 35 + if got := GetGeneralizedIndexForListElement(1, 16, 3); got != 35 { + t.Fatalf("list: got %d want 35", got) + } +} diff --git a/shared/types/eth2/generic/progressive.go b/shared/types/eth2/generic/progressive.go new file mode 100644 index 000000000..0931c2c1e --- /dev/null +++ b/shared/types/eth2/generic/progressive.go @@ -0,0 +1,98 @@ +package generic + +import "math/bits" + +// Progressive Merkle tree helpers for EIP-7495 ProgressiveContainer and +// EIP-7916 ProgressiveList / ProgressiveBitlist (adopted by EIP-7688 in Gloas). +// +// These replace classic Container/List g-indices only for types that the Gloas +// specs redefine as progressive. Pre-Gloas forks (Deneb/Electra/Fulu) must keep +// using the classic helpers in gindex.go (ContainerFieldGindex, +// GetGeneralizedIndexForValidator, etc.). +// +// Progressive tree shape (chunk capacities grow 1, 4, 16, 64, … on successive +// levels; each level is a binary subtree on the left with the next progressive +// level on the right): +// +// root +// /\ +// / \ +// +// L0 next0 // L0: chunks[0 .. 1) +// +// /\ +// +// L1 next1 // L1: chunks[1 .. 5) +// +// ProgressiveContainer root = hash(progressive_tree, active_fields) +// ProgressiveList root = hash(progressive_tree, length) + +// ConcatGindices concatenates generalized-index path steps the way remerkleable +// does: each step is a gindex relative to its own subtree root (root = 1). +func ConcatGindices(steps ...uint64) uint64 { + out := uint64(1) + for _, step := range steps { + if step < 1 { + // Invalid gindex; treat as no-op path to avoid panics. Callers must + // only pass valid gindices (>= 1). + continue + } + // Number of path bits after the leading 1. + stepBitLen := bits.Len64(step) - 1 + out <<= stepBitLen + out |= step ^ (uint64(1) << stepBitLen) + } + return out +} + +// ProgressiveChunkGindex returns the generalized index of chunk `index` within +// a progressive Merkle tree whose root is gindex 1 (EIP-7916). +func ProgressiveChunkGindex(index uint64) uint64 { + gindex := uint64(1) + start := uint64(0) + capacity := uint64(1) + for { + if index < start+capacity { + offset := index - start + // Left into this level's binary subtree, then to the leaf. + gindex = gindex * 2 + gindex = gindex*capacity + offset + return gindex + } + // Right into the next progressive level. + gindex = gindex*2 + 1 + start += capacity + capacity *= 4 + } +} + +// ProgressiveContainerFieldGindex returns the generalized index of field +// `fieldIndex` (its ssz-index) within a ProgressiveContainer whose root is +// gindex 1. The progressive tree of field roots is the left child; active_fields +// is mixed in on the right. +func ProgressiveContainerFieldGindex(fieldIndex uint64) uint64 { + return ConcatGindices(2, ProgressiveChunkGindex(fieldIndex)) +} + +// ProgressiveListElementGindex returns the generalized index of element +// `elementIndex` within a ProgressiveList whose root is gindex 1. The progressive +// tree of elements is the left child; the list length is mixed in on the right. +// +// This is the index of the Merkle chunk for that element. For ProgressiveList of +// composite types (e.g. Validator), each element is one chunk so elementIndex is +// used directly. For basic types that pack into 32-byte chunks (e.g. uint64 packs +// 4 per leaf), pass the packed chunk index instead of the raw element index. +func ProgressiveListElementGindex(elementIndex uint64) uint64 { + return ConcatGindices(2, ProgressiveChunkGindex(elementIndex)) +} + +// GetGeneralizedIndexForProgressiveListElement returns the gindex of an element +// inside a ProgressiveList that itself sits at listRootGindex in a larger tree +// (e.g. a ProgressiveContainer field). See ProgressiveListElementGindex for +// packing notes on basic vs composite element types. +// +// Gloas only for ProgressiveList fields. Fixed-capacity List navigation (including +// Gloas historical_summaries) uses GetGeneralizedIndexForListElement in gindex.go. +func GetGeneralizedIndexForProgressiveListElement(listRootGindex uint64, elementIndex uint64) uint64 { + return ConcatGindices(listRootGindex, ProgressiveListElementGindex(elementIndex)) +} diff --git a/shared/types/eth2/generic/progressive_test.go b/shared/types/eth2/generic/progressive_test.go new file mode 100644 index 000000000..229a0b650 --- /dev/null +++ b/shared/types/eth2/generic/progressive_test.go @@ -0,0 +1,158 @@ +package generic + +import ( + "bytes" + "testing" + + "github.com/pk910/dynamic-ssz/treeproof" +) + +func TestConcatGindices(t *testing.T) { + if got := ConcatGindices(); got != 1 { + t.Fatalf("empty: got %d want 1", got) + } + if got := ConcatGindices(1); got != 1 { + t.Fatalf("root only: got %d want 1", got) + } + // Left of root, then left again: 1 -> 2 -> 4 + if got := ConcatGindices(2, 2); got != 4 { + t.Fatalf("concat(2,2): got %d want 4", got) + } + // Progressive field 1: progressive tree at 2, chunk gindex 24 + if got := ConcatGindices(2, 24); got != 40 { + t.Fatalf("concat(2,24): got %d want 40", got) + } +} + +func TestProgressiveChunkGindex(t *testing.T) { + cases := []struct { + index uint64 + want uint64 + }{ + {0, 2}, + {1, 24}, + {2, 25}, + {3, 26}, + {4, 27}, + {5, 224}, + {11, 230}, + {27, 1926}, + {44, 1943}, + } + for _, tc := range cases { + if got := ProgressiveChunkGindex(tc.index); got != tc.want { + t.Errorf("ProgressiveChunkGindex(%d): got %d want %d", tc.index, got, tc.want) + } + } +} + +func TestProgressiveContainerFieldGindex(t *testing.T) { + // Known Gloas BeaconState field gindices (ssz-index → absolute from root). + cases := []struct { + field uint64 + want uint64 + }{ + {0, 4}, // genesis_time + {1, 40}, // genesis_validators_root + {2, 41}, // slot + {5, 352}, // block_roots + {11, 358}, // validators + {27, 2950}, // historical_summaries + {44, 2967}, // payload_expected_withdrawals + } + for _, tc := range cases { + if got := ProgressiveContainerFieldGindex(tc.field); got != tc.want { + t.Errorf("ProgressiveContainerFieldGindex(%d): got %d want %d", tc.field, got, tc.want) + } + } +} + +func TestProgressiveListElementGindex(t *testing.T) { + // Element 0: left of progressive tree at list root → concat(2, 2) = 4 + if got := ProgressiveListElementGindex(0); got != 4 { + t.Fatalf("element 0: got %d want 4", got) + } + // Element 1: concat(2, 24) = 40 + if got := ProgressiveListElementGindex(1); got != 40 { + t.Fatalf("element 1: got %d want 40", got) + } +} + +// progressiveItem is a fixed composite so each ProgressiveList element is one +// Merkle leaf (basic types pack multiple values per chunk). +type progressiveItem struct { + X uint64 + Y uint64 +} + +// progressiveProbe is a ProgressiveContainer with a ProgressiveList of composites +// so we can verify gindices against real treeproof nodes. +type progressiveProbe struct { + A uint64 `ssz-index:"0"` + B uint64 `ssz-index:"1"` + C uint64 `ssz-index:"2"` + D []*progressiveItem `ssz-type:"progressive-list" ssz-max:"1024" ssz-index:"5"` +} + +func TestProgressiveGindicesMatchTree(t *testing.T) { + obj := &progressiveProbe{ + A: 0x11, + B: 0x22, + C: 0x33, + D: []*progressiveItem{ + {X: 100, Y: 1}, + {X: 200, Y: 2}, + {X: 300, Y: 3}, + }, + } + + tree, err := SSZ.GetTree(obj) + if err != nil { + t.Fatalf("GetTree: %v", err) + } + + // Field A (ssz-index 0) + gidA := ProgressiveContainerFieldGindex(0) + proofA, err := tree.Prove(int(gidA)) + if err != nil { + t.Fatalf("Prove field A (gid=%d): %v", gidA, err) + } + if ok, err := treeproof.VerifyProof(tree.Hash(), proofA); err != nil || !ok { + t.Fatalf("verify field A: ok=%v err=%v leaf=%x", ok, err, proofA.Leaf) + } + + // Field B (ssz-index 1) + gidB := ProgressiveContainerFieldGindex(1) + proofB, err := tree.Prove(int(gidB)) + if err != nil { + t.Fatalf("Prove field B (gid=%d): %v", gidB, err) + } + if ok, err := treeproof.VerifyProof(tree.Hash(), proofB); err != nil || !ok { + t.Fatalf("verify field B: ok=%v err=%v", ok, err) + } + + // Field D element 1 (ssz-index 5 progressive list of composites) + gidD := ProgressiveContainerFieldGindex(5) + gidD1 := GetGeneralizedIndexForProgressiveListElement(gidD, 1) + proofD1, err := tree.Prove(int(gidD1)) + if err != nil { + t.Fatalf("Prove D[1] (gid=%d): %v", gidD1, err) + } + itemRoot, err := SSZ.HashTreeRoot(obj.D[1]) + if err != nil { + t.Fatalf("HTR D[1]: %v", err) + } + if !bytes.Equal(proofD1.Leaf, itemRoot[:]) { + t.Fatalf("D[1] leaf mismatch: got %x want %x", proofD1.Leaf, itemRoot) + } + if ok, err := treeproof.VerifyProof(tree.Hash(), proofD1); err != nil || !ok { + t.Fatalf("verify D[1]: ok=%v err=%v", ok, err) + } + + // Sanity: progressive field gindex must differ from old power-of-two container + // layout (ceil(6 fields)=8 + 5 = 13). + oldStyle := uint64(8 + 5) + if gidD == oldStyle { + t.Fatalf("progressive field gindex unexpectedly equals old-style %d", oldStyle) + } +} diff --git a/shared/types/eth2/generic/state.go b/shared/types/eth2/generic/state.go index 3a1d90ca1..01b3ea414 100644 --- a/shared/types/eth2/generic/state.go +++ b/shared/types/eth2/generic/state.go @@ -1,18 +1,25 @@ package generic +// Shared BeaconState field offsets. These offsets are stable from Capella through +// Gloas for the fields Smart Node proves against; only the *merkleization* of the +// parent container changes in Gloas + // BeaconStateValidatorsIndex is the field offset of the Validators field in the BeaconState struct const BeaconStateValidatorsIndex uint64 = 11 -// SlotIndex is the field offset of the Slot field in the BeaconState struct +// BeaconStateSlotIndex is the field offset of the Slot field in the BeaconState struct const BeaconStateSlotIndex uint64 = 2 -// If this ever isn't a power of two, we need to round up to the next power of two +// beaconStateValidatorsMaxLength is VALIDATOR_REGISTRY_LIMIT (mainnet List capacity) +// used by pre-Gloas fixed-capacity List[Validator, N] merkleization. const beaconStateValidatorsMaxLength uint64 = 1 << 40 const BeaconStateHistoricalSummariesFieldIndex uint64 = 27 const BeaconStateHistoricalSummariesMaxLength uint64 = 1 << 24 const BeaconStateBlockRootsMaxLength uint64 = 1 << 13 const BeaconStateBlockRootsFieldIndex uint64 = 5 +const BeaconStateStateRootsMaxLength uint64 = 1 << 13 +const BeaconStateStateRootsFieldIndex uint64 = 6 type PendingDeposit struct { Pubkey []byte `json:"pubkey" ssz-size:"48"` diff --git a/shared/types/eth2/generic/validator.go b/shared/types/eth2/generic/validator.go deleted file mode 100644 index 9940c6cd5..000000000 --- a/shared/types/eth2/generic/validator.go +++ /dev/null @@ -1,18 +0,0 @@ -package generic - -import ( - "github.com/rocket-pool/smartnode/shared/math" -) - -func GetGeneralizedIndexForValidator(index uint64, validatorsArrayIndex uint64) uint64 { - root := validatorsArrayIndex - - // Now, grab the validator index within the list - // `start` is `index * 32` and `pos` is `start / 32` so pos is just `index` - pos := index - baseIndex := uint64(2) // Lists have a base index of 2 - root = root*baseIndex*math.GetPowerOfTwoCeil(beaconStateValidatorsMaxLength) + pos - - // root is now the generalized index for the validator - return root -} diff --git a/shared/types/eth2/types.go b/shared/types/eth2/types.go index a873e1c3b..22e0fc671 100644 --- a/shared/types/eth2/types.go +++ b/shared/types/eth2/types.go @@ -8,17 +8,20 @@ import ( "github.com/rocket-pool/smartnode/shared/types/eth2/fork/deneb" "github.com/rocket-pool/smartnode/shared/types/eth2/fork/electra" "github.com/rocket-pool/smartnode/shared/types/eth2/fork/fulu" + "github.com/rocket-pool/smartnode/shared/types/eth2/fork/gloas" "github.com/rocket-pool/smartnode/shared/types/eth2/generic" ) // State type assertions var _ BeaconState = &electra.BeaconState{} var _ BeaconState = &fulu.BeaconState{} +var _ BeaconState = &gloas.BeaconState{} // Block type assertions var _ SignedBeaconBlock = &deneb.SignedBeaconBlock{} var _ SignedBeaconBlock = &electra.SignedBeaconBlock{} var _ SignedBeaconBlock = &fulu.SignedBeaconBlock{} +var _ SignedBeaconBlock = &gloas.SignedBeaconBlock{} type BeaconState interface { GetSlot() uint64 @@ -76,6 +79,13 @@ func NewBeaconState(data io.ReadCloser, size int64, fork string) (BeaconState, e return nil, err } return out, nil + case "gloas": + out := &gloas.BeaconState{} + err := decodeSSZ(out, data, size) + if err != nil { + return nil, err + } + return out, nil default: _ = data.Close() return nil, fmt.Errorf("unsupported fork: %s", fork) @@ -107,6 +117,13 @@ func NewSignedBeaconBlock(data io.ReadCloser, size int64, fork string) (SignedBe return nil, err } return out, nil + case "gloas": + out := &gloas.SignedBeaconBlock{} + err := decodeSSZ(out, data, size) + if err != nil { + return nil, err + } + return out, nil default: _ = data.Close() return nil, fmt.Errorf("unsupported fork: %s", fork) diff --git a/sszgen.sh b/sszgen.sh index 6e5d32eb1..dd322aa86 100755 --- a/sszgen.sh +++ b/sszgen.sh @@ -13,17 +13,21 @@ DYNSSZ_GEN="go tool dynssz-gen" find ./shared/types/eth2 -name "*_generated.go" -delete $DYNSSZ_GEN -package ./shared/types/eth2/generic -with-streaming \ - -types "Fork,BeaconBlockHeader,Eth1Data,Validator,Checkpoint,SyncCommittee,HistoricalSummary,HistoricalSummaryLists,ExecutionPayloadHeader,PendingDeposit,PendingPartialWithdrawal,PendingConsolidation,ProposerSlashing,SignedBeaconBlockHeader,AttesterSlashing,IndexedAttestation,AttestationData,Attestation,Deposit,SignedVoluntaryExit,SyncAggregate,ExecutionPayload,Withdrawal,BLSToExecutionChange,SignedBLSToExecutionChange,DepositDataNoSignature,DepositData,SigningRoot,VoluntaryExit,WithdrawalCredentialsChange,Uint256" \ - -output ./shared/types/eth2/generic/generic_generated.go +-types "Fork,BeaconBlockHeader,Eth1Data,Validator,Checkpoint,SyncCommittee,HistoricalSummary,HistoricalSummaryLists,ExecutionPayloadHeader,PendingDeposit,PendingPartialWithdrawal,PendingConsolidation,ProposerSlashing,SignedBeaconBlockHeader,AttesterSlashing,IndexedAttestation,AttestationData,Attestation,Deposit,SignedVoluntaryExit,SyncAggregate,ExecutionPayload,Withdrawal,BLSToExecutionChange,SignedBLSToExecutionChange,DepositDataNoSignature,DepositData,SigningRoot,VoluntaryExit,WithdrawalCredentialsChange,Uint256" \ +-output ./shared/types/eth2/generic/generic_generated.go $DYNSSZ_GEN -package ./shared/types/eth2/fork/deneb -with-streaming \ - -types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,ExecutionPayload" \ - -output ./shared/types/eth2/fork/deneb/deneb_generated.go +-types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,ExecutionPayload" \ +-output ./shared/types/eth2/fork/deneb/deneb_generated.go $DYNSSZ_GEN -package ./shared/types/eth2/fork/electra -with-streaming \ - -types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,Attestation,ExecutionRequests,DepositRequest,WithdrawalRequest,ConsolidationRequest,AttesterSlashing,IndexedAttestation" \ - -output ./shared/types/eth2/fork/electra/electra_generated.go +-types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,Attestation,ExecutionRequests,DepositRequest,WithdrawalRequest,ConsolidationRequest,AttesterSlashing,IndexedAttestation" \ +-output ./shared/types/eth2/fork/electra/electra_generated.go $DYNSSZ_GEN -package ./shared/types/eth2/fork/fulu -with-streaming \ - -types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,Attestation,ExecutionRequests,DepositRequest,WithdrawalRequest,ConsolidationRequest,AttesterSlashing,IndexedAttestation" \ - -output ./shared/types/eth2/fork/fulu/fulu_generated.go +-types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,Attestation,ExecutionRequests,DepositRequest,WithdrawalRequest,ConsolidationRequest,AttesterSlashing,IndexedAttestation" \ +-output ./shared/types/eth2/fork/fulu/fulu_generated.go + +$DYNSSZ_GEN -package ./shared/types/eth2/fork/gloas -with-streaming \ +-types "BeaconState,SignedBeaconBlock,BeaconBlock,BeaconBlockBody,Builder,BuilderPendingWithdrawal,BuilderPendingPayment,Attestation,ExecutionPayloadBid,SignedExecutionPayloadBid,PayloadAttestationData,PayloadAttestation,ExecutionRequests,DepositRequest,WithdrawalRequest,ConsolidationRequest,BuilderDepositRequest,BuilderExitRequest,AttesterSlashing,IndexedAttestation" \ +-output ./shared/types/eth2/fork/gloas/gloas_generated.go diff --git a/treegen/tree-gen.go b/treegen/tree-gen.go index 45e0e031f..7d79ffe4a 100644 --- a/treegen/tree-gen.go +++ b/treegen/tree-gen.go @@ -653,12 +653,17 @@ func (g *treeGenerator) getSnapshotDetails() (*snapshotDetails, error) { endTime := g.slotToTime(g.targets.block.Slot) - // Get the number of the EL block matching the CL snapshot block + // Get the number of the EL block matching the CL snapshot block. Gloas blocks only commit to + // the EL block hash, so the number has to be resolved. var snapshotElBlockHeader *types.Header - if g.targets.block.ExecutionBlockNumber == 0 { + elBlockNumber, hasElBlock, err := beacon.ResolveExecutionBlockNumber(context.Background(), g.rp, *g.targets.block) + if err != nil { + return nil, err + } + if !hasElBlock { return nil, fmt.Errorf("slot %d was pre-merge", g.targets.block.Slot) } - opts.BlockNumber = big.NewInt(0).SetUint64(g.targets.block.ExecutionBlockNumber) + opts.BlockNumber = big.NewInt(0).SetUint64(elBlockNumber) snapshotElBlockHeader, err = g.rp.HeaderByNumber(context.Background(), opts.BlockNumber) if err != nil { return nil, fmt.Errorf("error getting EL block %d: %w", opts.BlockNumber.Uint64(), err)