From 1414c2c64e76539275a434bc6012aeca2aabdc8c Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Mon, 17 Aug 2026 18:15:37 -0300 Subject: [PATCH 1/2] Consume github rewards event files --- bindings/rewards/event-file.go | 247 +++++++ bindings/rewards/event-file_test.go | 253 +++++++ bindings/rewards/rewards.go | 671 +----------------- rocketpool/api/debug/rewards-event.go | 2 +- .../watchtower/generate-rewards-tree.go | 4 +- .../watchtower/submit-network-balances.go | 2 +- .../submit-rewards-tree-stateless.go | 2 +- shared/services/config/smartnode-config.go | 17 + shared/services/rewards/execution-client.go | 18 +- shared/services/rewards/utils.go | 2 +- treegen/tree-gen.go | 2 +- 11 files changed, 543 insertions(+), 677 deletions(-) create mode 100644 bindings/rewards/event-file.go create mode 100644 bindings/rewards/event-file_test.go diff --git a/bindings/rewards/event-file.go b/bindings/rewards/event-file.go new file mode 100644 index 000000000..cdff84b70 --- /dev/null +++ b/bindings/rewards/event-file.go @@ -0,0 +1,247 @@ +package rewards + +import ( + "fmt" + "io" + "math/big" + "net/http" + "os" + "path/filepath" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "gopkg.in/yaml.v2" +) + +const ( + networkMainnet = "mainnet" + networkTestnet = "testnet" + + rewardsEventLocalFilenameFormat = "rp-rewards-event-%s-%d.yaml" + rewardsEventRemoteFilenameFormat = "rp-rewards-event-%d.yaml" +) + +var ( + rewardsEventFileURLFormat = "https://github.com/rocket-pool/rewards-trees/raw/main/%s/%s" + rewardsEventDownloadTimeouts = []time.Duration{200 * time.Millisecond, 2 * time.Second, 60 * time.Second} +) + +var rewardsEventFileLock sync.Mutex + +// On-disk / GitHub encoding of a RewardSnapshot event. +type rewardsEventFile struct { + Index string `yaml:"index"` + ExecutionBlock string `yaml:"executionBlock"` + ConsensusBlock string `yaml:"consensusBlock"` + MerkleRoot string `yaml:"merkleRoot"` + IntervalsPassed string `yaml:"intervalsPassed"` + TreasuryRPL string `yaml:"treasuryRPL"` + TrustedNodeRPL []string `yaml:"trustedNodeRPL"` + NodeRPL []string `yaml:"nodeRPL"` + NodeETH []string `yaml:"nodeETH"` + UserETH string `yaml:"userETH"` + IntervalStartTime int64 `yaml:"intervalStartTime"` + IntervalEndTime int64 `yaml:"intervalEndTime"` + SubmissionTime int64 `yaml:"submissionTime"` +} + +func supportsRewardsEventFile(network string) bool { + return network == networkMainnet || network == networkTestnet +} + +func rewardsEventLocalPath(cacheDir, network string, index uint64) string { + return filepath.Join(cacheDir, fmt.Sprintf(rewardsEventLocalFilenameFormat, network, index)) +} + +func rewardsEventRemoteURL(network string, index uint64) string { + return fmt.Sprintf(rewardsEventFileURLFormat, network, fmt.Sprintf(rewardsEventRemoteFilenameFormat, index)) +} + +// Load a rewards event from the local cache or GitHub. A miss (ok=false, err=nil) +// means the caller should fall through to the execution-client log query. +func getIntervalRewardsEvent(index uint64, network, cacheDir string) (RewardsEvent, bool, error) { + if !supportsRewardsEventFile(network) { + return RewardsEvent{}, false, nil + } + + rewardsEventFileLock.Lock() + defer rewardsEventFileLock.Unlock() + + var localPath string + if cacheDir != "" { + localPath = rewardsEventLocalPath(cacheDir, network, index) + if event, ok, err := readRewardsEventFile(localPath, index); err == nil && ok { + return event, true, nil + } + } + + event, raw, ok, err := downloadRewardsEventFile(network, index) + if err != nil { + return RewardsEvent{}, false, err + } + if !ok { + return RewardsEvent{}, false, nil + } + + if localPath != "" { + if writeErr := writeRewardsEventFile(localPath, raw); writeErr != nil { + return RewardsEvent{}, false, fmt.Errorf("error caching rewards event file %s: %w", localPath, writeErr) + } + } + return event, true, nil +} + +func readRewardsEventFile(path string, expectedIndex uint64) (RewardsEvent, bool, error) { + bytes, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + return RewardsEvent{}, false, nil + } + return RewardsEvent{}, false, err + } + event, err := parseRewardsEventFile(bytes, expectedIndex) + if err != nil { + return RewardsEvent{}, false, err + } + return event, true, nil +} + +func writeRewardsEventFile(path string, raw []byte) error { + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + tmp, err := os.CreateTemp(filepath.Dir(path), filepath.Base(path)+".*.tmp") + if err != nil { + return err + } + tmpName := tmp.Name() + if _, err := tmp.Write(raw); err != nil { + tmp.Close() + os.Remove(tmpName) + return err + } + if err := tmp.Close(); err != nil { + os.Remove(tmpName) + return err + } + return os.Rename(tmpName, path) +} + +func downloadRewardsEventFile(network string, index uint64) (RewardsEvent, []byte, bool, error) { + url := rewardsEventRemoteURL(network, index) + for _, timeout := range rewardsEventDownloadTimeouts { + client := http.Client{ + Timeout: timeout, + } + resp, err := client.Get(url) + if err != nil { + continue + } + body, readErr := io.ReadAll(resp.Body) + resp.Body.Close() + if readErr != nil { + continue + } + if resp.StatusCode == http.StatusNotFound { + return RewardsEvent{}, nil, false, nil + } + if resp.StatusCode != http.StatusOK { + continue + } + event, err := parseRewardsEventFile(body, index) + if err != nil { + return RewardsEvent{}, nil, false, fmt.Errorf("error parsing rewards event file from %s: %w", url, err) + } + return event, body, true, nil + } + // Treat persistent download failures as a miss so the execution-client path can run. + return RewardsEvent{}, nil, false, nil +} + +func parseRewardsEventFile(raw []byte, expectedIndex uint64) (RewardsEvent, error) { + var file rewardsEventFile + if err := yaml.Unmarshal(raw, &file); err != nil { + return RewardsEvent{}, fmt.Errorf("error unmarshaling rewards event yaml: %w", err) + } + + index, err := parseBigInt(file.Index) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid index: %w", err) + } + if index.Uint64() != expectedIndex { + return RewardsEvent{}, fmt.Errorf("rewards event file index %s does not match requested interval %d", file.Index, expectedIndex) + } + + executionBlock, err := parseBigInt(file.ExecutionBlock) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid executionBlock: %w", err) + } + consensusBlock, err := parseBigInt(file.ConsensusBlock) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid consensusBlock: %w", err) + } + intervalsPassed, err := parseBigInt(file.IntervalsPassed) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid intervalsPassed: %w", err) + } + treasuryRPL, err := parseBigInt(file.TreasuryRPL) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid treasuryRPL: %w", err) + } + userETH, err := parseBigInt(file.UserETH) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid userETH: %w", err) + } + trustedNodeRPL, err := parseBigIntSlice(file.TrustedNodeRPL) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid trustedNodeRPL: %w", err) + } + nodeRPL, err := parseBigIntSlice(file.NodeRPL) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid nodeRPL: %w", err) + } + nodeETH, err := parseBigIntSlice(file.NodeETH) + if err != nil { + return RewardsEvent{}, fmt.Errorf("invalid nodeETH: %w", err) + } + + return RewardsEvent{ + Index: index, + ExecutionBlock: executionBlock, + ConsensusBlock: consensusBlock, + IntervalsPassed: intervalsPassed, + TreasuryRPL: treasuryRPL, + TrustedNodeRPL: trustedNodeRPL, + NodeRPL: nodeRPL, + NodeETH: nodeETH, + UserETH: userETH, + MerkleRoot: common.HexToHash(file.MerkleRoot), + IntervalStartTime: time.Unix(file.IntervalStartTime, 0), + IntervalEndTime: time.Unix(file.IntervalEndTime, 0), + SubmissionTime: time.Unix(file.SubmissionTime, 0), + }, nil +} + +func parseBigInt(s string) (*big.Int, error) { + if s == "" { + return big.NewInt(0), nil + } + v, ok := new(big.Int).SetString(s, 10) + if !ok { + return nil, fmt.Errorf("%q is not a valid integer", s) + } + return v, nil +} + +func parseBigIntSlice(values []string) ([]*big.Int, error) { + out := make([]*big.Int, len(values)) + for i, s := range values { + v, err := parseBigInt(s) + if err != nil { + return nil, err + } + out[i] = v + } + return out, nil +} diff --git a/bindings/rewards/event-file_test.go b/bindings/rewards/event-file_test.go new file mode 100644 index 000000000..5aa7bffb9 --- /dev/null +++ b/bindings/rewards/event-file_test.go @@ -0,0 +1,253 @@ +package rewards + +import ( + "math/big" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "sync/atomic" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" +) + +const interval0YAML = `index: '0' +executionBlock: '15451078' +consensusBlock: '4598879' +merkleRoot: '0xb839fa0f5842bf3c8f19091361889fb0f1cb399d64b8da476d372b7de7a93463' +intervalsPassed: '1' +treasuryRPL: '10633670478560109530497' +trustedNodeRPL: +- '10633670478560109529794' +nodeRPL: +- '49623795566613844471758' +nodeETH: +- '0' +userETH: '0' +intervalStartTime: 1659591339 +intervalEndTime: 1662010539 +submissionTime: 1662011717 +` + +const interval44YAML = `index: '44' +executionBlock: '24238059' +consensusBlock: '13469279' +merkleRoot: '0x72ed38107b2b6c1a0469800af741c04adf5563aebe5a0ae5d77fb9b2354c64a5' +intervalsPassed: '1' +treasuryRPL: '22719124146910393305039' +trustedNodeRPL: +- '2065374922446399391296' +nodeRPL: +- '57830497828499182955594' +nodeETH: +- '15367476931278801422' +userETH: '4223474559072201135' +intervalStartTime: 1766036139 +intervalEndTime: 1768455339 +submissionTime: 1768461851 +` + +func TestParseRewardsEventFileInterval44(t *testing.T) { + event, err := parseRewardsEventFile([]byte(interval44YAML), 44) + if err != nil { + t.Fatalf("parse: %v", err) + } + assertBig(t, "index", event.Index, "44") + assertBig(t, "executionBlock", event.ExecutionBlock, "24238059") + assertBig(t, "consensusBlock", event.ConsensusBlock, "13469279") + assertBig(t, "intervalsPassed", event.IntervalsPassed, "1") + assertBig(t, "treasuryRPL", event.TreasuryRPL, "22719124146910393305039") + assertBig(t, "userETH", event.UserETH, "4223474559072201135") + if len(event.TrustedNodeRPL) != 1 { + t.Fatalf("trustedNodeRPL len = %d", len(event.TrustedNodeRPL)) + } + assertBig(t, "trustedNodeRPL[0]", event.TrustedNodeRPL[0], "2065374922446399391296") + assertBig(t, "nodeRPL[0]", event.NodeRPL[0], "57830497828499182955594") + assertBig(t, "nodeETH[0]", event.NodeETH[0], "15367476931278801422") + wantRoot := common.HexToHash("0x72ed38107b2b6c1a0469800af741c04adf5563aebe5a0ae5d77fb9b2354c64a5") + if event.MerkleRoot != wantRoot { + t.Fatalf("merkleRoot = %s, want %s", event.MerkleRoot.Hex(), wantRoot.Hex()) + } + if event.IntervalStartTime.Unix() != 1766036139 { + t.Fatalf("intervalStartTime = %d", event.IntervalStartTime.Unix()) + } + if event.IntervalEndTime.Unix() != 1768455339 { + t.Fatalf("intervalEndTime = %d", event.IntervalEndTime.Unix()) + } + if event.SubmissionTime.Unix() != 1768461851 { + t.Fatalf("submissionTime = %d", event.SubmissionTime.Unix()) + } +} + +func TestParseRewardsEventFileInterval0(t *testing.T) { + event, err := parseRewardsEventFile([]byte(interval0YAML), 0) + if err != nil { + t.Fatalf("parse: %v", err) + } + assertBig(t, "treasuryRPL", event.TreasuryRPL, "10633670478560109530497") + assertBig(t, "userETH", event.UserETH, "0") + assertBig(t, "nodeETH[0]", event.NodeETH[0], "0") + if event.MerkleRoot != common.HexToHash("0xb839fa0f5842bf3c8f19091361889fb0f1cb399d64b8da476d372b7de7a93463") { + t.Fatalf("merkleRoot = %s", event.MerkleRoot.Hex()) + } +} + +func TestParseRewardsEventFileIndexMismatch(t *testing.T) { + _, err := parseRewardsEventFile([]byte(interval44YAML), 43) + if err == nil { + t.Fatal("expected index mismatch error") + } +} + +func TestGetIntervalRewardsEventUnsupportedNetwork(t *testing.T) { + event, ok, err := getIntervalRewardsEvent(44, "devnet", t.TempDir()) + if err != nil { + t.Fatalf("err = %v", err) + } + if ok { + t.Fatalf("expected miss for devnet, got %+v", event) + } + _, ok, err = getIntervalRewardsEvent(44, "", t.TempDir()) + if err != nil || ok { + t.Fatalf("expected miss for empty network, ok=%v err=%v", ok, err) + } +} + +func TestGetIntervalRewardsEventCacheHit(t *testing.T) { + cacheDir := t.TempDir() + path := rewardsEventLocalPath(cacheDir, networkMainnet, 44) + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte(interval44YAML), 0644); err != nil { + t.Fatal(err) + } + + var hits atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hits.Add(1) + t.Errorf("unexpected HTTP request: %s", r.URL.Path) + http.NotFound(w, r) + })) + t.Cleanup(server.Close) + overrideEventFileURL(t, server.URL+"/%s/%s") + + event, ok, err := getIntervalRewardsEvent(44, networkMainnet, cacheDir) + if err != nil { + t.Fatalf("err = %v", err) + } + if !ok { + t.Fatal("expected cache hit") + } + assertBig(t, "executionBlock", event.ExecutionBlock, "24238059") + if hits.Load() != 0 { + t.Fatalf("HTTP was called %d times", hits.Load()) + } +} + +func TestGetIntervalRewardsEventDownloadAndCache(t *testing.T) { + for _, network := range []string{networkMainnet, networkTestnet} { + t.Run(network, func(t *testing.T) { + var hits atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hits.Add(1) + want := "/" + network + "/rp-rewards-event-44.yaml" + if r.URL.Path != want { + t.Errorf("path = %s, want %s", r.URL.Path, want) + http.NotFound(w, r) + return + } + w.Write([]byte(interval44YAML)) + })) + t.Cleanup(server.Close) + overrideEventFileURL(t, server.URL+"/%s/%s") + + cacheDir := t.TempDir() + event, ok, err := getIntervalRewardsEvent(44, network, cacheDir) + if err != nil { + t.Fatalf("err = %v", err) + } + if !ok { + t.Fatal("expected download hit") + } + assertBig(t, "executionBlock", event.ExecutionBlock, "24238059") + + cached := rewardsEventLocalPath(cacheDir, network, 44) + if _, err := os.Stat(cached); err != nil { + t.Fatalf("expected cached file at %s: %v", cached, err) + } + + // Second call should be a cache hit. + _, ok, err = getIntervalRewardsEvent(44, network, cacheDir) + if err != nil || !ok { + t.Fatalf("second call: ok=%v err=%v", ok, err) + } + if hits.Load() != 1 { + t.Fatalf("HTTP hits = %d, want 1", hits.Load()) + } + }) + } +} + +func TestGetIntervalRewardsEventNotFoundIsMiss(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r) + })) + t.Cleanup(server.Close) + overrideEventFileURL(t, server.URL+"/%s/%s") + + _, ok, err := getIntervalRewardsEvent(44, networkTestnet, t.TempDir()) + if err != nil { + t.Fatalf("404 should be a miss, not an error: %v", err) + } + if ok { + t.Fatal("expected miss on 404") + } +} + +func TestGetIntervalRewardsEventDownloadFailureIsMiss(t *testing.T) { + overrideEventFileURL(t, "http://127.0.0.1:1/%s/%s") + origTimeouts := rewardsEventDownloadTimeouts + rewardsEventDownloadTimeouts = []time.Duration{20 * time.Millisecond} + t.Cleanup(func() { rewardsEventDownloadTimeouts = origTimeouts }) + + _, ok, err := getIntervalRewardsEvent(44, networkMainnet, t.TempDir()) + if err != nil { + t.Fatalf("download failure should be a miss, not an error: %v", err) + } + if ok { + t.Fatal("expected miss on download failure") + } +} + +func TestGetIntervalRewardsEventInvalidRemoteYAML(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("not: [valid")) + })) + t.Cleanup(server.Close) + overrideEventFileURL(t, server.URL+"/%s/%s") + + _, ok, err := getIntervalRewardsEvent(44, networkMainnet, t.TempDir()) + if err == nil { + t.Fatal("expected parse error for invalid remote yaml") + } + if ok { + t.Fatal("invalid yaml must not count as a hit") + } +} + +func overrideEventFileURL(t *testing.T, format string) { + t.Helper() + orig := rewardsEventFileURLFormat + rewardsEventFileURLFormat = format + t.Cleanup(func() { rewardsEventFileURLFormat = orig }) +} + +func assertBig(t *testing.T, name string, got *big.Int, want string) { + t.Helper() + if got == nil || got.String() != want { + t.Fatalf("%s = %v, want %s", name, got, want) + } +} diff --git a/bindings/rewards/rewards.go b/bindings/rewards/rewards.go index 7b25c2d86..c713158d5 100644 --- a/bindings/rewards/rewards.go +++ b/bindings/rewards/rewards.go @@ -1,7 +1,6 @@ package rewards import ( - "context" "fmt" "math/big" "slices" @@ -234,9 +233,9 @@ func SubmitRewardSnapshot(rp *rocketpool.RocketPool, submission RewardSubmission } // Get the event info for a rewards snapshot using the Atlas getter -func GetRewardsEvent(rp *rocketpool.RocketPool, index uint64, rocketRewardsPoolAddresses []common.Address, opts *bind.CallOpts) (bool, RewardsEvent, error) { - // Check if the client is requesting interval 0 on mainnet, then return the hardcoded RewardsEvent - data, ok, err := getMainnetIntervalRewardsEvent(rp, index) +func GetRewardsEvent(rp *rocketpool.RocketPool, index uint64, rocketRewardsPoolAddresses []common.Address, network string, eventCacheDir string, opts *bind.CallOpts) (bool, RewardsEvent, error) { + // Prefer a cached or GitHub-hosted event file. A miss falls through to the EL log query below. + data, ok, err := getIntervalRewardsEvent(index, network, eventCacheDir) if err != nil { return false, RewardsEvent{}, err } @@ -324,670 +323,6 @@ func GetRewardsEvent(rp *rocketpool.RocketPool, index uint64, rocketRewardsPoolA return true, eventData, nil } -// Check if the client is requesting a hardcoded interval on mainnet, then return the RewardsEvent -func getMainnetIntervalRewardsEvent(rp *rocketpool.RocketPool, index uint64) (RewardsEvent, bool, error) { - // Check if the ec is synced to mainnet - chainID, err := rp.Client.ChainID(context.Background()) - if err != nil { - return RewardsEvent{}, false, fmt.Errorf("error getting chainID: %w", err) - } - if chainID.Cmp(big.NewInt(1)) != 0 { - return RewardsEvent{}, false, nil - } - - var ( - merkleRoot common.Hash - intervalStartTime time.Time - intervalEndTime time.Time - submissionTime time.Time - ) - treasuryRPL := big.NewInt(0) - trustedNodeRPL := big.NewInt(0) - nodeRPL := big.NewInt(0) - nodeETH := big.NewInt(0) - userETH := big.NewInt(0) - var ( - executionBlock *big.Int - consensusBlock *big.Int - intervalsPassed *big.Int - ) - - // Hardcoded RewardsEvent for old intervals on mainnet - switch index { - case 0: - treasuryRPL.SetString("10633670478560109530497", 10) - trustedNodeRPL.SetString("10633670478560109529794", 10) - nodeRPL.SetString("49623795566613844471758", 10) - executionBlock = big.NewInt(15451078) - consensusBlock = big.NewInt(4598879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xb839fa0f5842bf3c8f19091361889fb0f1cb399d64b8da476d372b7de7a93463") - intervalStartTime = time.Unix(1659591339, 0) - intervalEndTime = time.Unix(1662010539, 0) - submissionTime = time.Unix(1662011717, 0) - userETH = big.NewInt(0) - case 1: - treasuryRPL.SetString("10550049308997708584809", 10) - trustedNodeRPL.SetString("10550049308997708584060", 10) - nodeRPL.SetString("49233563441989306724917", 10) - nodeETH.SetString("55886528290134709468", 10) - executionBlock = big.NewInt(15636954) - consensusBlock = big.NewInt(4800479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xb060f0964ce14117075608a69835f4e5e3b872936d3fba2dbb17e202b5c2a7d1") - intervalStartTime = time.Unix(1662010539, 0) - intervalEndTime = time.Unix(1664429739, 0) - submissionTime = time.Unix(1664436887, 0) - userETH.SetString("41139205675101362849", 10) - case 2: - treasuryRPL.SetString("10589610096624449116454", 10) - trustedNodeRPL.SetString("10589610096624449115610", 10) - nodeRPL.SetString("49418180450914095872087", 10) - nodeETH.SetString("120666426232176747457", 10) - executionBlock = big.NewInt(15837359) - consensusBlock = big.NewInt(5002079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x278fd75797e2a9eddc128c0199b448877e30d1196c12306bdc95fb731647c18f") - intervalStartTime = time.Unix(1664429739, 0) - intervalEndTime = time.Unix(1666848939, 0) - submissionTime = time.Unix(1666874939, 0) - userETH.SetString("88931841842952009134", 10) - case 3: - treasuryRPL.SetString("10629319230090323621908", 10) - trustedNodeRPL.SetString("10629319230090323621082", 10) - nodeRPL.SetString("49603489740421510230963", 10) - nodeETH.SetString("178060769200919879825", 10) - executionBlock = big.NewInt(16037791) - consensusBlock = big.NewInt(5203679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xc0c736dccc4371b8a9d4ded4b50213dd820504430350d157350f52dfd04869ab") - intervalStartTime = time.Unix(1666848939, 0) - intervalEndTime = time.Unix(1669268139, 0) - submissionTime = time.Unix(1669275119, 0) - userETH.SetString("131334112536558744486", 10) - case 4: - treasuryRPL.SetString("10669177265665550884567", 10) - trustedNodeRPL.SetString("10669177265665550883677", 10) - nodeRPL.SetString("49789493906439237456308", 10) - nodeETH.SetString("90137212013211727003", 10) - executionBlock = big.NewInt(16238190) - consensusBlock = big.NewInt(5405279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x21c047f0035a64ca5b21c42bdad08d329f2121b5f1fe47e51222f9701f373826") - intervalStartTime = time.Unix(1669268139, 0) - intervalEndTime = time.Unix(1671687339, 0) - submissionTime = time.Unix(1671695987, 0) - userETH.SetString("66619163202260233947", 10) - case 5: - treasuryRPL.SetString("10709184761706262970440", 10) - trustedNodeRPL.SetString("10709184761706262969440", 10) - nodeRPL.SetString("49976195554629227189775", 10) - nodeETH.SetString("100959865151123783128", 10) - executionBlock = big.NewInt(16438804) - consensusBlock = big.NewInt(5606879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xde0604812161f69253e6bdaf0f623c63e1d7c49d43a78b5333564b24dae2e450") - intervalStartTime = time.Unix(1671687339, 0) - intervalEndTime = time.Unix(1674106539, 0) - submissionTime = time.Unix(1674113807, 0) - userETH.SetString("74626075394052241951", 10) - case 6: - treasuryRPL.SetString("10749342278662327028056", 10) - trustedNodeRPL.SetString("10749342278662327026976", 10) - nodeRPL.SetString("50163597300424192791516", 10) - nodeETH.SetString("152862142797510957810", 10) - executionBlock = big.NewInt(16639245) - consensusBlock = big.NewInt(5808479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x804d82caab67b8bcfff14f044cb6745ed3ba59c5fd06f52c27b25c96c95e3290") - intervalStartTime = time.Unix(1674106539, 0) - intervalEndTime = time.Unix(1676525739, 0) - submissionTime = time.Unix(1676533163, 0) - userETH.SetString("112999364182148607952", 10) - case 7: - treasuryRPL.SetString("10789650379085196418454", 10) - trustedNodeRPL.SetString("10789650379085196417433", 10) - nodeRPL.SetString("50351701769064249947084", 10) - nodeETH.SetString("214889774917327718259", 10) - executionBlock = big.NewInt(16838374) - consensusBlock = big.NewInt(6010079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x64692e59bb20ed13f5401b659fb53868c319a9dad410cb5b3c35a99c56db0ba1") - intervalStartTime = time.Unix(1676525739, 0) - intervalEndTime = time.Unix(1678944939, 0) - submissionTime = time.Unix(1678986371, 0) - userETH.SetString("158900489644285001733", 10) - case 8: - treasuryRPL.SetString("10830109627635791285926", 10) - trustedNodeRPL.SetString("10830109627635791284908", 10) - nodeRPL.SetString("50540511595633692661988", 10) - nodeETH.SetString("124277451394130356705", 10) - executionBlock = big.NewInt(17036705) - consensusBlock = big.NewInt(6211679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x9e53fc60a6e330b8aece2d2475dcc23e17426c5a552c7b4374ddddd46fa6599b") - intervalStartTime = time.Unix(1678944939, 0) - intervalEndTime = time.Unix(1681364139, 0) - submissionTime = time.Unix(1681371923, 0) - userETH.SetString("91918564718913412697", 10) - case 9: - treasuryRPL.SetString("10870720591092408678629", 10) - trustedNodeRPL.SetString("10870720591092408677484", 10) - nodeRPL.SetString("50730029425097907160549", 10) - nodeETH.SetString("265294502885782199241", 10) - executionBlock = big.NewInt(17235076) - consensusBlock = big.NewInt(6413279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x2238938633ae1f6a3275b52492dc64018f2245912b708f91bd21cc8472fa3f45") - intervalStartTime = time.Unix(1681364139, 0) - intervalEndTime = time.Unix(1683783339, 0) - submissionTime = time.Unix(1683791075, 0) - userETH.SetString("251254537064420777704", 10) - case 10: - treasuryRPL.SetString("10911483838358662330962", 10) - trustedNodeRPL.SetString("10911483838358662329864", 10) - nodeRPL.SetString("50920257912340424204973", 10) - nodeETH.SetString("207224314619456280271", 10) - executionBlock = big.NewInt(17433555) - consensusBlock = big.NewInt(6614879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xc16b52575ec0494ef72ec419f7660f65d35abe65a51c277e3a8b4f581988ab25") - intervalStartTime = time.Unix(1683783339, 0) - intervalEndTime = time.Unix(1686202539, 0) - submissionTime = time.Unix(1686209267, 0) - userETH.SetString("244724588999515442961", 10) - case 11: - treasuryRPL.SetString("10952399940471452219796", 10) - trustedNodeRPL.SetString("10952399940471452218698", 10) - nodeRPL.SetString("51111199722200110352863", 10) - nodeETH.SetString("129839125242481699627", 10) - executionBlock = big.NewInt(17632767) - consensusBlock = big.NewInt(6816479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x280677fb18f06701851bd057f52558e59c6a8534f31bf0222e424dd4e2b6d2d2") - intervalStartTime = time.Unix(1686202539, 0) - intervalEndTime = time.Unix(1688621739, 0) - submissionTime = time.Unix(1688629187, 0) - userETH.SetString("168470911056744138735", 10) - case 12: - treasuryRPL.SetString("16123755223559813871223", 10) - trustedNodeRPL.SetString("5863183717658114134602", 10) - nodeRPL.SetString("51302857529508498676908", 10) - nodeETH.SetString("264844913795172053460", 10) - executionBlock = big.NewInt(17832425) - consensusBlock = big.NewInt(7018079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xae4e2bb2dc3efee5a20bedc83be1a7b5450de064867edae2aae59e1df08313fe") - intervalStartTime = time.Unix(1688621739, 0) - intervalEndTime = time.Unix(1691040939, 0) - submissionTime = time.Unix(1691045351, 0) - userETH.SetString("357819970818590187458", 10) - case 13: - treasuryRPL.SetString("16184216406011424405097", 10) - trustedNodeRPL.SetString("5885169602185972510578", 10) - nodeRPL.SetString("51495234019127259466761", 10) - nodeETH.SetString("218680806556832509553", 10) - executionBlock = big.NewInt(18032505) - consensusBlock = big.NewInt(7219679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x8e1a38feed2f3e88782a7bbb3ff24c650f3903beb3169c3d196b358ce70a9080") - intervalStartTime = time.Unix(1691040939, 0) - intervalEndTime = time.Unix(1693460139, 0) - submissionTime = time.Unix(1693462895, 0) - userETH.SetString("306490363490092102569", 10) - case 14: - treasuryRPL.SetString("16983309048252480903029", 10) - trustedNodeRPL.SetString("5168833188598581144102", 10) - nodeRPL.SetString("51688331885985811440053", 10) - nodeETH.SetString("174468095251348093682", 10) - executionBlock = big.NewInt(18232197) - consensusBlock = big.NewInt(7421279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x8b2e52188d616a19f50477d1d2d2e3ddc8a2a056f9486ec7cc25d7140c75217b") - intervalStartTime = time.Unix(1693460139, 0) - intervalEndTime = time.Unix(1695879339, 0) - submissionTime = time.Unix(1695887015, 0) - userETH.SetString("246414308218062973622", 10) - case 15: - treasuryRPL.SetString("17046993402967695740540", 10) - trustedNodeRPL.SetString("5188215383511907398948", 10) - nodeRPL.SetString("51882153835119073988521", 10) - nodeETH.SetString("113064713982751905771", 10) - executionBlock = big.NewInt(18432348) - consensusBlock = big.NewInt(7622879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xa1afd40dfecdde96b59d2a85eac5fd0c618bc336cdfad6ee9c093cf30a02335b") - intervalStartTime = time.Unix(1695879339, 0) - intervalEndTime = time.Unix(1698298539, 0) - submissionTime = time.Unix(1698299831, 0) - userETH.SetString("161261121697283843558", 10) - case 16: - treasuryRPL.SetString("17929264745987131427422", 10) - trustedNodeRPL.SetString("4389322074743737569096", 10) - nodeRPL.SetString("52076702581705360988290", 10) - nodeETH.SetString("145511116579242423330", 10) - executionBlock = big.NewInt(18632383) - consensusBlock = big.NewInt(7824479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x72515a30759d598e36aea4b2729ee38136da3da8c3d40c17e8ddaf6381746b61") - intervalStartTime = time.Unix(1698298539, 0) - intervalEndTime = time.Unix(1700717739, 0) - submissionTime = time.Unix(1700719223, 0) - userETH.SetString("208347503555437494510", 10) - case 17: - treasuryRPL.SetString("17996496264451663466746", 10) - trustedNodeRPL.SetString("4405781243164515122322", 10) - nodeRPL.SetString("52271980851104416704641", 10) - nodeETH.SetString("197988839753658327068", 10) - executionBlock = big.NewInt(18832201) - consensusBlock = big.NewInt(8026079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x8466396383460910d80e9a5af0b962213b3a0e33c4a41f3b817a84487364c123") - intervalStartTime = time.Unix(1700717739, 0) - intervalEndTime = time.Unix(1703136939, 0) - submissionTime = time.Unix(1703138135, 0) - userETH.SetString("285455180775757420844", 10) - case 18: - treasuryRPL.SetString("18063979889019768905884", 10) - trustedNodeRPL.SetString("4422302130506914378890", 10) - nodeRPL.SetString("52467991378895594323702", 10) - nodeETH.SetString("119998368939736398237", 10) - executionBlock = big.NewInt(19031703) - consensusBlock = big.NewInt(8227679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xd37ce5368a3790cfd9f3fff6a56079b0026a9a06f2fee02a5055f6838cfd5a00") - intervalStartTime = time.Unix(1703136939, 0) - intervalEndTime = time.Unix(1705556139, 0) - submissionTime = time.Unix(1705557263, 0) - userETH.SetString("175552968220321206323", 10) - case 19: - treasuryRPL.SetString("18131716565043998308966", 10) - trustedNodeRPL.SetString("4438884968205792116706", 10) - nodeRPL.SetString("52664736910916177654259", 10) - nodeETH.SetString("148353447414176591282", 10) - executionBlock = big.NewInt(19231284) - consensusBlock = big.NewInt(8429279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x35d1be64d49aa71dc5b5ea13dd6f91d8613c81aef2593796d6dee599cd228aea") - intervalStartTime = time.Unix(1705556139, 0) - intervalEndTime = time.Unix(1707975339, 0) - submissionTime = time.Unix(1707976475, 0) - userETH.SetString("219460060796213936870", 10) - case 20: - treasuryRPL.SetString("20691783336720225637003", 10) - trustedNodeRPL.SetString("1963453893265422870516", 10) - nodeRPL.SetString("52862220203299846512817", 10) - nodeETH.SetString("129970171333179451391", 10) - executionBlock = big.NewInt(19431215) - consensusBlock = big.NewInt(8630879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x55afb0387fb4c1c8e479f49433b996bce1d1c4658cf8e58f7a9ea3d3c5099eb2") - intervalStartTime = time.Unix(1707975339, 0) - intervalEndTime = time.Unix(1710394539, 0) - submissionTime = time.Unix(1710395711, 0) - userETH.SetString("194196448160947806147", 10) - case 21: - treasuryRPL.SetString("20769373803098840664266", 10) - trustedNodeRPL.SetString("1970816492264853493584", 10) - nodeRPL.SetString("53060444022515286364660", 10) - nodeETH.SetString("86124043557534943014", 10) - executionBlock = big.NewInt(19630338) - consensusBlock = big.NewInt(8832479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x7273138f110f464d45c3ec8b42aec0280b0e5a434a93907a5c9db047cb180866") - intervalStartTime = time.Unix(1710394539, 0) - intervalEndTime = time.Unix(1712813739, 0) - submissionTime = time.Unix(1712824835, 0) - userETH.SetString("129212548027034380183", 10) - case 22: - treasuryRPL.SetString("20847255219772791871405", 10) - trustedNodeRPL.SetString("1978206699686469301548", 10) - nodeRPL.SetString("53259411145404942733410", 10) - nodeETH.SetString("87118787916582229383", 10) - executionBlock = big.NewInt(19830438) - consensusBlock = big.NewInt(9034079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xc2724d07659bb0cb7bbc926b873a56226ebf368bea729c007e214f464e8aa69d") - intervalStartTime = time.Unix(1712813739, 0) - intervalEndTime = time.Unix(1715232939, 0) - submissionTime = time.Unix(1715234147, 0) - userETH.SetString("131641498401095297397", 10) - case 23: - treasuryRPL.SetString("20925428677753363338954", 10) - trustedNodeRPL.SetString("1985624619056888491962", 10) - nodeRPL.SetString("53459124359223920937447", 10) - nodeETH.SetString("82988716547997166273", 10) - executionBlock = big.NewInt(20030738) - consensusBlock = big.NewInt(9235679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xde037dafa7973dbab1cbe8cf46d85e2e125fd5bf193fc69b9f7811a5b6b7dc9d") - intervalStartTime = time.Unix(1715232939, 0) - intervalEndTime = time.Unix(1717652139, 0) - submissionTime = time.Unix(1717653455, 0) - userETH.SetString("125184956455787164441", 10) - case 24: - treasuryRPL.SetString("21847117345112177188009", 10) - trustedNodeRPL.SetString("1149848281321693536186", 10) - nodeRPL.SetString("53659586461679031688296", 10) - nodeETH.SetString("81335123762071854501", 10) - executionBlock = big.NewInt(20231099) - consensusBlock = big.NewInt(9437279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x2dccc9f3a86e7c857177c0f84abd314eeae162c398adcfbf5c94bd62812f1f1d") - intervalStartTime = time.Unix(1717652139, 0) - intervalEndTime = time.Unix(1720071339, 0) - submissionTime = time.Unix(1720072511, 0) - userETH.SetString("121962895985768410912", 10) - case 25: - treasuryRPL.SetString("21929040106251250266871", 10) - trustedNodeRPL.SetString("1154160005592171066642", 10) - nodeRPL.SetString("53860800260967983110475", 10) - nodeETH.SetString("59836872361825739644", 10) - executionBlock = big.NewInt(20431646) - consensusBlock = big.NewInt(9638879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xd8f3480bb44f993586001225adcc8f87f22d12184cd804d8f717dc9d26cacaa2") - intervalStartTime = time.Unix(1720071339, 0) - intervalEndTime = time.Unix(1722490539, 0) - submissionTime = time.Unix(1722491723, 0) - userETH.SetString("89677960178182813533", 10) - case 26: - treasuryRPL.SetString("22011270063011907313857", 10) - trustedNodeRPL.SetString("1158487898053258279638", 10) - nodeRPL.SetString("54062768575818719716793", 10) - nodeETH.SetString("73118591648836191604", 10) - executionBlock = big.NewInt(20632194) - consensusBlock = big.NewInt(9840479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xbffdc74404912050acccc79ec6556bd159f7a6f9db3be0c045519461c96047ef") - intervalStartTime = time.Unix(1722490539, 0) - intervalEndTime = time.Unix(1724909739, 0) - submissionTime = time.Unix(1724911139, 0) - userETH.SetString("109309541129377923619", 10) - case 27: - treasuryRPL.SetString("22093808367322484339645", 10) - trustedNodeRPL.SetString("1162832019332762333628", 10) - nodeRPL.SetString("54265494235528908903092", 10) - nodeETH.SetString("73502004443651237958", 10) - executionBlock = big.NewInt(20832734) - consensusBlock = big.NewInt(10042079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x19f080c89283f80aa29cef2155457400d3e1a3989a16108f214fbf0e1a683e13") - intervalStartTime = time.Unix(1724909739, 0) - intervalEndTime = time.Unix(1727328939, 0) - submissionTime = time.Unix(1727330339, 0) - userETH.SetString("109414335754265646582", 10) - case 28: - treasuryRPL.SetString("22176656175430841456904", 10) - trustedNodeRPL.SetString("1167192430285833760860", 10) - nodeRPL.SetString("54468980080005575506939", 10) - nodeETH.SetString("65852251763664532329", 10) - executionBlock = big.NewInt(21033406) - consensusBlock = big.NewInt(10243679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x5fd98bc90296e3ebcdf7098a539f3c04388aa639d885bacfea2b088796375d8c") - intervalStartTime = time.Unix(1727328939, 0) - intervalEndTime = time.Unix(1729748139, 0) - submissionTime = time.Unix(1729749551, 0) - userETH.SetString("97856965684776269348", 10) - case 29: - treasuryRPL.SetString("22259814647920560318926", 10) - trustedNodeRPL.SetString("1171569191995818964092", 10) - nodeRPL.SetString("54673228959804884990101", 10) - nodeETH.SetString("71988611161220176226", 10) - executionBlock = big.NewInt(21234057) - consensusBlock = big.NewInt(10445279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x82e89c1b2cfa0248ee5d2ff9bd4b0013388bc0da2005ee03e666c83c7bb51a92") - intervalStartTime = time.Unix(1729748139, 0) - intervalEndTime = time.Unix(1732167339, 0) - submissionTime = time.Unix(1732168487, 0) - userETH.SetString("114014988744595356456", 10) - case 30: - treasuryRPL.SetString("22343284949727202292854", 10) - trustedNodeRPL.SetString("1175962365775115910096", 10) - nodeRPL.SetString("54878243736172075803559", 10) - nodeETH.SetString("69245099392448778466", 10) - executionBlock = big.NewInt(21434520) - consensusBlock = big.NewInt(10646879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x021b434c4f6bc565225d03d77ba722f41668f5805574f8825c49d4f68b4e89b9") - intervalStartTime = time.Unix(1732167339, 0) - intervalEndTime = time.Unix(1734586539, 0) - submissionTime = time.Unix(1734594971, 0) - userETH.SetString("93870760781122417496", 10) - case 31: - treasuryRPL.SetString("22427068250154627605694", 10) - trustedNodeRPL.SetString("1180372013166033031824", 10) - nodeRPL.SetString("55084027281081541484240", 10) - nodeETH.SetString("60850105918353222556", 10) - executionBlock = big.NewInt(21634996) - consensusBlock = big.NewInt(10848479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x6502a89b162c41b1cbc019aaa82c6c1e76f872bfca0cd7dfd688bf217b9a820d") - intervalStartTime = time.Unix(1734586539, 0) - intervalEndTime = time.Unix(1737005739, 0) - submissionTime = time.Unix(1737017999, 0) - userETH.SetString("78963743041980491460", 10) - case 32: - treasuryRPL.SetString("22511165722891375675992", 10) - trustedNodeRPL.SetString("1184798195941651351312", 10) - nodeRPL.SetString("55290582477277063060540", 10) - nodeETH.SetString("61524968493175262980", 10) - executionBlock = big.NewInt(21835515) - consensusBlock = big.NewInt(11050079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x44941bda178c03ca6d8a5e72fd9433fd566ac801d57cb5ccb8d833436bc07f95") - intervalStartTime = time.Unix(1737005739, 0) - intervalEndTime = time.Unix(1739424939, 0) - submissionTime = time.Unix(1739436551, 0) - userETH.SetString("78337779811500941545", 10) - case 33: - treasuryRPL.SetString("22595578546027106873451", 10) - trustedNodeRPL.SetString("1189240976106689835392", 10) - nodeRPL.SetString("55497912218312192317529", 10) - nodeETH.SetString("133016473781938819503", 10) - executionBlock = big.NewInt(22035900) - consensusBlock = big.NewInt(11251679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x6c71cf2beb6bf80c90a0bed50b2eff376919bf3016ac5102ce403a4bd74c35b3") - intervalStartTime = time.Unix(1739424939, 0) - intervalEndTime = time.Unix(1741844139, 0) - submissionTime = time.Unix(1741856879, 0) - userETH.SetString("192141107613389949606", 10) - case 34: - treasuryRPL.SetString("21884507624803523266610", 10) - trustedNodeRPL.SetString("1989500693163956660512", 10) - nodeRPL.SetString("55706019408590786493514", 10) - nodeETH.SetString("51299429061085367685", 10) - executionBlock = big.NewInt(22236473) - consensusBlock = big.NewInt(11453279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x0311e81c20f7161dd37db58cec5108bc687ba7b4352ccbc797a04028b08fd8a1") - intervalStartTime = time.Unix(1741844139, 0) - intervalEndTime = time.Unix(1744263339, 0) - submissionTime = time.Unix(1744283327, 0) - userETH.SetString("60649284015156972974", 10) - case 35: - treasuryRPL.SetString("21966570592767308741140", 10) - trustedNodeRPL.SetString("1996960962978846249104", 10) - nodeRPL.SetString("55914906963407694974189", 10) - nodeETH.SetString("38282673601408514244", 10) - executionBlock = big.NewInt(22436785) - consensusBlock = big.NewInt(11654879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x057eb4b982774871cd1aefd2962589620fee1e9cfcbf36d0f08e292da837dc49") - intervalStartTime = time.Unix(1744263339, 0) - intervalEndTime = time.Unix(1746682539, 0) - submissionTime = time.Unix(1746691523, 0) - userETH.SetString("38934754761348367759", 10) - case 36: - treasuryRPL.SetString("22048941282103056576253", 10) - trustedNodeRPL.SetString("2004449207463914234114", 10) - nodeRPL.SetString("56124577808989598554500", 10) - executionBlock = big.NewInt(22636374) - consensusBlock = big.NewInt(11856479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x704c7c2f6faeb97b20535a9a325e9ba573ec066ee579853b3e94b175114a8fd7") - intervalStartTime = time.Unix(1746682539, 0) - intervalEndTime = time.Unix(1749101739, 0) - submissionTime = time.Unix(1749113279, 0) - nodeETH.SetString("50039863506253385959", 10) - userETH.SetString("57244908435972245571", 10) - case 37: - treasuryRPL.SetString("22131620846710572152925", 10) - trustedNodeRPL.SetString("2011965531519142922898", 10) - nodeRPL.SetString("56335034882536001840574", 10) - nodeETH.SetString("45418705066756834715", 10) - executionBlock = big.NewInt(22836652) - consensusBlock = big.NewInt(12058079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xf4db744c50762a7ae1b19ee26120a582207eb1c535614711aae4cc5c598e42cf") - intervalStartTime = time.Unix(1749101739, 0) - intervalEndTime = time.Unix(1751520939, 0) - submissionTime = time.Unix(1751532611, 0) - userETH.SetString("48318015461156177248", 10) - case 38: - treasuryRPL.SetString("22214610444816577609208", 10) - trustedNodeRPL.SetString("2019510040437870691659", 10) - nodeRPL.SetString("56546281132260379365673", 10) - nodeETH.SetString("40700127824685134045", 10) - executionBlock = big.NewInt(23037044) - consensusBlock = big.NewInt(12259679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xf7809e999791fb6c73712c7d281624020ba773dc144fdfbb41c86b2e3cbb42fd") - intervalStartTime = time.Unix(1751520939, 0) - intervalEndTime = time.Unix(1753940139, 0) - submissionTime = time.Unix(1753948367, 0) - userETH.SetString("40528725716465757725", 10) - case 39: - treasuryRPL.SetString("22297911238990936999935", 10) - trustedNodeRPL.SetString("2027082839908266999911", 10) - nodeRPL.SetString("56758319517431475996754", 10) - nodeETH.SetString("34921409718655333629", 10) - executionBlock = big.NewInt(23237567) - consensusBlock = big.NewInt(12461279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xec51162c8af79d86e4b8f6546ec0e1ec3b4172b12574893e938c4f5bdd408efe") - intervalStartTime = time.Unix(1753940139, 0) - intervalEndTime = time.Unix(1756359339, 0) - submissionTime = time.Unix(1756395407, 0) - userETH.SetString("31594532680318853963", 10) - case 40: - // {"status":"success","error":"","found":true,"index":"40","executionBlock":"23438005","consensusBlock":"12662879","merkleRoot":"0x2ad908aa47f988d09dd9884c8026e6213262e231bab0d5051eedb2bef6aefe1e","intervalsPassed":"1","treasuryRPL":"22381524396162942297937","trustedNodeRPL":["2034684036014812936091"],"nodeRPL":["56971153008414762209929"],"nodeETH":["24246940457789627532"],"userETH":"13888515305764133572","intervalStartTime":1756359339,"intervalEndTime":1758778539,"submissionTime":1758785783} - treasuryRPL.SetString("22381524396162942297937", 10) - trustedNodeRPL.SetString("2034684036014812936091", 10) - nodeRPL.SetString("56971153008414762209929", 10) - nodeETH.SetString("24246940457789627532", 10) - executionBlock = big.NewInt(23438005) - consensusBlock = big.NewInt(12662879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x2ad908aa47f988d09dd9884c8026e6213262e231bab0d5051eedb2bef6aefe1e") - intervalStartTime = time.Unix(1756359339, 0) - intervalEndTime = time.Unix(1758778539, 0) - submissionTime = time.Unix(1758785783, 0) - userETH.SetString("13888515305764133572", 10) - case 41: - treasuryRPL.SetString("22465451087637660464639", 10) - trustedNodeRPL.SetString("2042313735239787314880", 10) - nodeRPL.SetString("57184784586714044816063", 10) - nodeETH.SetString("43676270282606810107", 10) - executionBlock = big.NewInt(23638162) - consensusBlock = big.NewInt(12864479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xe8af8737484cfd3d3fd5106ef189333e92f9bbc2de0ac057f4c01c473b2ec958") - intervalStartTime = time.Unix(1758778539, 0) - intervalEndTime = time.Unix(1761197739, 0) - submissionTime = time.Unix(1761205211, 0) - userETH.SetString("47268078777290226308", 10) - case 42: - treasuryRPL.SetString("22549692489112341819332", 10) - trustedNodeRPL.SetString("2049972044464758347124", 10) - nodeRPL.SetString("57399217245013233718952", 10) - nodeETH.SetString("25631914712861974454", 10) - executionBlock = big.NewInt(23838215) - consensusBlock = big.NewInt(13066079) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x9f8c89596b48d377279bf703444a2e0cd5e98ac4cc0f5c490324c394c1ba3ce8") - intervalStartTime = time.Unix(1761197739, 0) - intervalEndTime = time.Unix(1763616939, 0) - submissionTime = time.Unix(1763642831, 0) - userETH.SetString("17561894202841328207", 10) - case 43: - treasuryRPL.SetString("22634249780692889936981", 10) - trustedNodeRPL.SetString("2057659070972080903284", 10) - nodeRPL.SetString("57614453987218265291225", 10) - nodeETH.SetString("18947687367286040081", 10) - executionBlock = big.NewInt(24037441) - consensusBlock = big.NewInt(13267679) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0xa98c94badfa30d41fcde8a3c5ccdadadbe441e43883919567b2d45682e476ca3") - intervalStartTime = time.Unix(1763616939, 0) - intervalEndTime = time.Unix(1766036139, 0) - submissionTime = time.Unix(1766046599, 0) - userETH.SetString("8352566574518930988", 10) - case 44: - treasuryRPL.SetString("22719124146910393305039", 10) - trustedNodeRPL.SetString("2065374922446399391296", 10) - nodeRPL.SetString("57830497828499182955594", 10) - nodeETH.SetString("15367476931278801422", 10) - executionBlock = big.NewInt(24238059) - consensusBlock = big.NewInt(13469279) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x72ed38107b2b6c1a0469800af741c04adf5563aebe5a0ae5d77fb9b2354c64a5") - intervalStartTime = time.Unix(1766036139, 0) - intervalEndTime = time.Unix(1768455339, 0) - submissionTime = time.Unix(1768461851, 0) - userETH.SetString("4223474559072201135", 10) - case 45: - treasuryRPL.SetString("22804316776737718971210", 10) - trustedNodeRPL.SetString("2073119706976156270036", 10) - nodeRPL.SetString("58047351795332375560374", 10) - nodeETH.SetString("28550894583322805236", 10) - executionBlock = big.NewInt(24438645) - consensusBlock = big.NewInt(13670879) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x97dc8f589c86c3650a96568ab05c08a9e160aec7eb405e35ec2e62c6e1af559c") - intervalStartTime = time.Unix(1768455339, 0) - intervalEndTime = time.Unix(1770874539, 0) - submissionTime = time.Unix(1770894827, 0) - userETH.SetString("22178758316567204991", 10) - case 46: - treasuryRPL.SetString("22889828863606168413868", 10) - trustedNodeRPL.SetString("2080893533055106219373", 10) - nodeRPL.SetString("58265018925542974141956", 10) - nodeETH.SetString("19997007660595265346", 10) - executionBlock = big.NewInt(24639334) - consensusBlock = big.NewInt(13872479) - intervalsPassed = big.NewInt(1) - merkleRoot = common.HexToHash("0x8cb45bcefd498b8788e6291c4dc086694c85b495fb60e9d5b047e7b921929d48") - intervalStartTime = time.Unix(1770874539, 0) - intervalEndTime = time.Unix(1773293739, 0) - submissionTime = time.Unix(1773299819, 0) - userETH.SetString("12369109587853762785", 10) - default: - return RewardsEvent{}, false, nil - } - - eventDataInterval := RewardsEvent{ - Index: big.NewInt(int64(index)), - ExecutionBlock: executionBlock, - ConsensusBlock: consensusBlock, - IntervalsPassed: intervalsPassed, - TreasuryRPL: treasuryRPL, - TrustedNodeRPL: []*big.Int{trustedNodeRPL}, - NodeRPL: []*big.Int{nodeRPL}, - NodeETH: []*big.Int{nodeETH}, - UserETH: userETH, - MerkleRoot: merkleRoot, - IntervalStartTime: intervalStartTime, - IntervalEndTime: intervalEndTime, - SubmissionTime: submissionTime, - } - - return eventDataInterval, true, nil -} - // Get contracts var rocketRewardsPoolLock sync.Mutex diff --git a/rocketpool/api/debug/rewards-event.go b/rocketpool/api/debug/rewards-event.go index e059f3222..ff1721df5 100644 --- a/rocketpool/api/debug/rewards-event.go +++ b/rocketpool/api/debug/rewards-event.go @@ -22,7 +22,7 @@ func getRewardsEvent(c *cli.Command, interval uint64) (*api.RewardsEventResponse } previousRewardsPoolAddresses := cfg.Smartnode.GetPreviousRewardsPoolAddresses() - rewardsClient := rprewards.NewRewardsExecutionClient(rp) + rewardsClient := rprewards.NewRewardsExecutionClientFromConfig(rp, cfg) event, err := rewardsClient.GetRewardSnapshotEvent(previousRewardsPoolAddresses, interval, nil) if err != nil { diff --git a/rocketpool/watchtower/generate-rewards-tree.go b/rocketpool/watchtower/generate-rewards-tree.go index 4ed37e3e9..acaf8d028 100644 --- a/rocketpool/watchtower/generate-rewards-tree.go +++ b/rocketpool/watchtower/generate-rewards-tree.go @@ -142,7 +142,7 @@ func (t *generateRewardsTree) generateRewardsTree(index uint64) { // Get previous rewards pool addresses previousRewardsPoolAddresses := t.cfg.Smartnode.GetPreviousRewardsPoolAddresses() - rewardsClient := rprewards.NewRewardsExecutionClient(t.rp) + rewardsClient := rprewards.NewRewardsExecutionClientFromConfig(t.rp, t.cfg) // Find the event for this interval rewardsEvent, err := rewardsClient.GetRewardSnapshotEvent(previousRewardsPoolAddresses, index, nil) @@ -241,7 +241,7 @@ func (t *generateRewardsTree) generateRewardsTreeImpl(rp *rocketpool.RocketPool, // Generate the rewards file start := time.Now() - treegen, err := rprewards.NewTreeGenerator(&t.log, generationPrefix, rprewards.NewRewardsExecutionClient(rp), t.cfg, t.bc, index, rewardsEvent.IntervalStartTime, rewardsEvent.IntervalEndTime, snapshotEnd, elBlockHeader, rewardsEvent.IntervalsPassed.Uint64(), state) + treegen, err := rprewards.NewTreeGenerator(&t.log, generationPrefix, rprewards.NewRewardsExecutionClientFromConfig(rp, t.cfg), t.cfg, t.bc, index, rewardsEvent.IntervalStartTime, rewardsEvent.IntervalEndTime, snapshotEnd, elBlockHeader, rewardsEvent.IntervalsPassed.Uint64(), state) if err != nil { t.handleError(fmt.Errorf("%s Error creating Merkle tree generator: %w", generationPrefix, err)) return diff --git a/rocketpool/watchtower/submit-network-balances.go b/rocketpool/watchtower/submit-network-balances.go index 7b05d6cea..392cb80d9 100644 --- a/rocketpool/watchtower/submit-network-balances.go +++ b/rocketpool/watchtower/submit-network-balances.go @@ -111,7 +111,7 @@ func (c *liveSmoothingPoolCalculator) GetSmoothingPoolShare(ns *state.NetworkSta ExecutionBlock: ns.ElBlockNumber, } - treegen, err := rprewards.NewTreeGenerator(c.log, "[Balances]", rprewards.NewRewardsExecutionClient(c.client), c.cfg, c.bc, currentIndex, startTime, endTime, snapshotEnd, elBlockHeader, uint64(intervalsPassed), ns) + treegen, err := rprewards.NewTreeGenerator(c.log, "[Balances]", rprewards.NewRewardsExecutionClientFromConfig(c.client, c.cfg), c.cfg, c.bc, currentIndex, startTime, endTime, snapshotEnd, elBlockHeader, uint64(intervalsPassed), ns) if err != nil { return nil, fmt.Errorf("error creating merkle tree generator to approximate share of smoothing pool: %w", err) } diff --git a/rocketpool/watchtower/submit-rewards-tree-stateless.go b/rocketpool/watchtower/submit-rewards-tree-stateless.go index 08ed00444..6bb0c23c2 100644 --- a/rocketpool/watchtower/submit-rewards-tree-stateless.go +++ b/rocketpool/watchtower/submit-rewards-tree-stateless.go @@ -328,7 +328,7 @@ func (t *submitRewardsTree_Stateless) generateTreeImpl(rp *rocketpool.RocketPool } // Generate the rewards file - treegen, err := rprewards.NewTreeGenerator(t.log, t.generationPrefix, rprewards.NewRewardsExecutionClient(rp), t.cfg, t.bc, currentIndex, startTime, endTime, snapshotEnd, snapshotElBlockHeader, uint64(intervalsPassed), state) + treegen, err := rprewards.NewTreeGenerator(t.log, t.generationPrefix, rprewards.NewRewardsExecutionClientFromConfig(rp, t.cfg), t.cfg, t.bc, currentIndex, startTime, endTime, snapshotEnd, snapshotElBlockHeader, uint64(intervalsPassed), state) if err != nil { return fmt.Errorf("Error creating Merkle tree generator: %w", err) } diff --git a/shared/services/config/smartnode-config.go b/shared/services/config/smartnode-config.go index e55f13334..db4197016 100644 --- a/shared/services/config/smartnode-config.go +++ b/shared/services/config/smartnode-config.go @@ -29,6 +29,8 @@ const ( rewardsTreeFilenameFormat string = "rp-rewards-%s-%d%s" minipoolPerformanceFilenameFormat string = "rp-minipool-performance-%s-%d%s" performanceFilenameFormat string = "rp-performance-%s-%d%s" + rewardsEventFilenameFormat string = "rp-rewards-event-%s-%d.yaml" + rewardsEventRemoteFilenameFormat string = "rp-rewards-event-%d.yaml" RewardsTreeIpfsExtension string = ".zst" RewardsTreesFolder string = "rewards-trees" ChecksumTableFilename string = "checksums.sha384" @@ -854,6 +856,21 @@ func (cfg *SmartnodeConfig) GetRewardsTreePath(interval uint64, daemon bool, ext ) } +func (cfg *SmartnodeConfig) GetRewardsEventFilename(interval uint64) string { + return fmt.Sprintf(rewardsEventFilenameFormat, string(cfg.Network.Value.(config.Network)), interval) +} + +func (cfg *SmartnodeConfig) GetRewardsEventRemoteFilename(interval uint64) string { + return fmt.Sprintf(rewardsEventRemoteFilenameFormat, interval) +} + +func (cfg *SmartnodeConfig) GetRewardsEventPath(interval uint64, daemon bool) string { + return filepath.Join( + cfg.GetRewardsTreeDirectory(daemon), + cfg.GetRewardsEventFilename(interval), + ) +} + func (cfg *SmartnodeConfig) GetMinipoolPerformancePath(interval uint64, daemon bool) string { return filepath.Join( cfg.GetRewardsTreeDirectory(daemon), diff --git a/shared/services/rewards/execution-client.go b/shared/services/rewards/execution-client.go index 1d6661829..7e1970b55 100644 --- a/shared/services/rewards/execution-client.go +++ b/shared/services/rewards/execution-client.go @@ -13,6 +13,8 @@ import ( "github.com/rocket-pool/smartnode/bindings/rewards" "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/bindings/settings/trustednode" + "github.com/rocket-pool/smartnode/shared/services/config" + cfgtypes "github.com/rocket-pool/smartnode/shared/types/config" ) // Interface assertion @@ -27,14 +29,26 @@ var _ RewardsExecutionClient = &defaultRewardsExecutionClient{} // in tests. type defaultRewardsExecutionClient struct { *rocketpool.RocketPool + network string + eventCacheDir string } -func NewRewardsExecutionClient(rp *rocketpool.RocketPool) RewardsExecutionClient { +func NewRewardsExecutionClient(rp *rocketpool.RocketPool, network string, eventCacheDir string) RewardsExecutionClient { out := new(defaultRewardsExecutionClient) out.RocketPool = rp + out.network = network + out.eventCacheDir = eventCacheDir return out } +func NewRewardsExecutionClientFromConfig(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfig) RewardsExecutionClient { + return NewRewardsExecutionClient( + rp, + string(cfg.Smartnode.Network.Value.(cfgtypes.Network)), + cfg.Smartnode.GetRewardsTreeDirectory(true), + ) +} + func (client *defaultRewardsExecutionClient) GetNetworkEnabled(networkId *big.Int, opts *bind.CallOpts) (bool, error) { return trustednode.GetNetworkEnabled(client.RocketPool, networkId, opts) } @@ -48,7 +62,7 @@ func (client *defaultRewardsExecutionClient) HeaderByHash(ctx context.Context, h } 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) + found, rewardsEvent, err := rewards.GetRewardsEvent(client.RocketPool, index, rocketRewardsPoolAddresses, client.network, client.eventCacheDir, opts) if err == nil && found { return found, rewardsEvent, nil } diff --git a/shared/services/rewards/utils.go b/shared/services/rewards/utils.go index 64541c75c..d62d56e4d 100644 --- a/shared/services/rewards/utils.go +++ b/shared/services/rewards/utils.go @@ -85,7 +85,7 @@ func GetIntervalInfo(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfig, no previousRewardsPoolAddresses := cfg.Smartnode.GetPreviousRewardsPoolAddresses() // Get the event details for this interval - client := NewRewardsExecutionClient(rp) + client := NewRewardsExecutionClientFromConfig(rp, cfg) event, err = client.GetRewardSnapshotEvent(previousRewardsPoolAddresses, interval, opts) if err != nil { return diff --git a/treegen/tree-gen.go b/treegen/tree-gen.go index 7d79ffe4a..3349fbdc1 100644 --- a/treegen/tree-gen.go +++ b/treegen/tree-gen.go @@ -171,7 +171,7 @@ func GenerateTree(c *cli.Command) error { generator := treeGenerator{ log: &logger, errLog: &errLogger, - rp: rprewards.NewRewardsExecutionClient(rp), + rp: rprewards.NewRewardsExecutionClientFromConfig(rp, cfg), rpNative: rp, cfg: cfg, bn: bn, From fabe173573f206437a02c947bf5150ec55bb7d22 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Mon, 17 Aug 2026 19:08:25 -0300 Subject: [PATCH 2/2] Fix lint errors --- bindings/rewards/event-file.go | 6 +++--- bindings/rewards/event-file_test.go | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bindings/rewards/event-file.go b/bindings/rewards/event-file.go index cdff84b70..12d5625f4 100644 --- a/bindings/rewards/event-file.go +++ b/bindings/rewards/event-file.go @@ -118,11 +118,11 @@ func writeRewardsEventFile(path string, raw []byte) error { tmpName := tmp.Name() if _, err := tmp.Write(raw); err != nil { tmp.Close() - os.Remove(tmpName) + _ = os.Remove(tmpName) return err } if err := tmp.Close(); err != nil { - os.Remove(tmpName) + _ = os.Remove(tmpName) return err } return os.Rename(tmpName, path) @@ -139,7 +139,7 @@ func downloadRewardsEventFile(network string, index uint64) (RewardsEvent, []byt continue } body, readErr := io.ReadAll(resp.Body) - resp.Body.Close() + _ = resp.Body.Close() if readErr != nil { continue } diff --git a/bindings/rewards/event-file_test.go b/bindings/rewards/event-file_test.go index 5aa7bffb9..bc58d2a5c 100644 --- a/bindings/rewards/event-file_test.go +++ b/bindings/rewards/event-file_test.go @@ -159,7 +159,9 @@ func TestGetIntervalRewardsEventDownloadAndCache(t *testing.T) { http.NotFound(w, r) return } - w.Write([]byte(interval44YAML)) + if _, err := w.Write([]byte(interval44YAML)); err != nil { + t.Errorf("write response: %v", err) + } })) t.Cleanup(server.Close) overrideEventFileURL(t, server.URL+"/%s/%s") @@ -224,7 +226,9 @@ func TestGetIntervalRewardsEventDownloadFailureIsMiss(t *testing.T) { func TestGetIntervalRewardsEventInvalidRemoteYAML(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("not: [valid")) + if _, err := w.Write([]byte("not: [valid")); err != nil { + t.Errorf("write response: %v", err) + } })) t.Cleanup(server.Close) overrideEventFileURL(t, server.URL+"/%s/%s")