@@ -3,11 +3,79 @@ package api
33import (
44 "context"
55 "os"
6+ "strings"
67 "time"
78
9+ "github.com/onflow/cadence"
810 "github.com/onflow/rosetta/log"
911)
1012
13+ // validateFeeReceivers checks the configured fee addresses (the FlowFees
14+ // contract account plus .contracts.fee_receivers) against the fee receiver
15+ // accounts the FlowFees contract rotates deposits across on chain. If an
16+ // on-chain receiver is missing from the config, fee deposits to it would be
17+ // misclassified as ordinary transfers, so we exit with a fatal error.
18+ // Configured addresses that are no longer on chain are fine — they may be
19+ // needed to classify fees in historical blocks.
20+ func (s * Server ) validateFeeReceivers (ctx context.Context ) {
21+ if s .Offline {
22+ return
23+ }
24+ client := s .DataAccessNodes .Client ()
25+ const attempts = 5
26+ for attempt := 1 ; attempt <= attempts ; attempt ++ {
27+ select {
28+ case <- ctx .Done ():
29+ return
30+ default :
31+ }
32+ if attempt > 1 {
33+ time .Sleep (time .Duration (attempt ) * time .Second )
34+ }
35+ latest , err := client .LatestBlockHeader (ctx )
36+ if err != nil {
37+ log .Errorf ("Failed to get the latest block header to validate fee receivers: %s" , err )
38+ continue
39+ }
40+ resp , err := client .Execute (ctx , latest .Id , s .scriptGetFeeReceivers , nil )
41+ if err != nil {
42+ log .Errorf ("Failed to execute the get_fee_receivers script: %s" , err )
43+ continue
44+ }
45+ arr , ok := resp .(cadence.Array )
46+ if ! ok {
47+ log .Errorf ("Failed to convert get_fee_receivers result to an array: got %T" , resp )
48+ return
49+ }
50+ onchain := []string {}
51+ missing := []string {}
52+ for _ , val := range arr .Values {
53+ addr , ok := val .(cadence.Address )
54+ if ! ok {
55+ log .Errorf ("Failed to convert get_fee_receivers element to an address: got %T" , val )
56+ return
57+ }
58+ onchain = append (onchain , addr .String ())
59+ if ! s .feeAddrs [string (addr .Bytes ())] {
60+ missing = append (missing , addr .String ())
61+ }
62+ }
63+ if len (missing ) > 0 {
64+ log .Fatalf (
65+ "On-chain fee receiver account(s) %s are missing from the configured fee addresses: " +
66+ "fee deposits to them would be misclassified as transfers; add them to .contracts.fee_receivers" ,
67+ strings .Join (missing , ", " ),
68+ )
69+ }
70+ log .Infof (
71+ "Validated the configured fee addresses against the on-chain fee receivers: %s" ,
72+ strings .Join (onchain , ", " ),
73+ )
74+ return
75+ }
76+ log .Errorf ("Giving up on fee receiver validation after %d attempts" , attempts )
77+ }
78+
1179// NOTE(tav): We exit with a fatal error if the on-chain state doesn't match
1280// what we expect. This assumes that we can trust the data returned to us by the
1381// Access API servers, which may not necessarily be true.
0 commit comments