@@ -2,12 +2,14 @@ package watchtower
22
33import (
44 "context"
5+ "fmt"
56 "math/big"
67 "strconv"
78 "testing"
89 "time"
910
1011 "github.com/ethereum/go-ethereum"
12+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
1113 "github.com/ethereum/go-ethereum/common"
1214 "github.com/ethereum/go-ethereum/core/types"
1315 "github.com/rocket-pool/smartnode/bindings/rocketpool"
@@ -771,3 +773,211 @@ func TestFindNextSubmissionTarget_AlreadySubmittedForBlock(t *testing.T) {
771773 t .Error ("expected valid=false when targetBlockNumber <= lastSubmissionBlock" )
772774 }
773775}
776+
777+ // ============================================================
778+ // hasSubmittedBlockBalances / hasSubmittedSpecificBlockBalances
779+ // ============================================================
780+
781+ // stubStorage is an in-memory storageGetter used by tests.
782+ type stubStorage struct {
783+ values map [[32 ]byte ]bool
784+ err error
785+ }
786+
787+ func (s * stubStorage ) GetBool (_ * bind.CallOpts , key [32 ]byte ) (bool , error ) {
788+ if s .err != nil {
789+ return false , s .err
790+ }
791+ return s .values [key ], nil
792+ }
793+
794+ func TestHasSubmittedBlockBalances_NotSubmitted (t * testing.T ) {
795+ storage := & stubStorage {values : map [[32 ]byte ]bool {}}
796+ task := & submitNetworkBalances {storage : storage }
797+
798+ got , err := task .hasSubmittedBlockBalances (common .HexToAddress ("0x1234" ), 12345 )
799+ if err != nil {
800+ t .Fatalf ("unexpected error: %v" , err )
801+ }
802+ if got {
803+ t .Error ("expected false when the block has not been submitted" )
804+ }
805+ }
806+
807+ func TestHasSubmittedBlockBalances_Submitted (t * testing.T ) {
808+ nodeAddr := common .HexToAddress ("0x1234" )
809+ blockNumber := uint64 (12345 )
810+ key := blockBalancesKey (nodeAddr , blockNumber )
811+
812+ storage := & stubStorage {values : map [[32 ]byte ]bool {key : true }}
813+ task := & submitNetworkBalances {storage : storage }
814+
815+ got , err := task .hasSubmittedBlockBalances (nodeAddr , blockNumber )
816+ if err != nil {
817+ t .Fatalf ("unexpected error: %v" , err )
818+ }
819+ if ! got {
820+ t .Error ("expected true when the block has been submitted" )
821+ }
822+ }
823+
824+ func TestHasSubmittedBlockBalances_DifferentNodeOrBlock (t * testing.T ) {
825+ nodeAddr := common .HexToAddress ("0xAAAA" )
826+ blockNumber := uint64 (500 )
827+ key := blockBalancesKey (nodeAddr , blockNumber )
828+
829+ storage := & stubStorage {values : map [[32 ]byte ]bool {key : true }}
830+ task := & submitNetworkBalances {storage : storage }
831+
832+ // Same block, different node → should not match
833+ gotOtherNode , err := task .hasSubmittedBlockBalances (common .HexToAddress ("0xBBBB" ), blockNumber )
834+ if err != nil {
835+ t .Fatalf ("unexpected error: %v" , err )
836+ }
837+ if gotOtherNode {
838+ t .Error ("expected false for a different node address" )
839+ }
840+
841+ // Same node, different block → should not match
842+ gotOtherBlock , err := task .hasSubmittedBlockBalances (nodeAddr , blockNumber + 1 )
843+ if err != nil {
844+ t .Fatalf ("unexpected error: %v" , err )
845+ }
846+ if gotOtherBlock {
847+ t .Error ("expected false for a different block number" )
848+ }
849+ }
850+
851+ func TestHasSubmittedBlockBalances_PropagatesError (t * testing.T ) {
852+ storage := & stubStorage {err : fmt .Errorf ("storage unavailable" )}
853+ task := & submitNetworkBalances {storage : storage }
854+
855+ _ , err := task .hasSubmittedBlockBalances (common .HexToAddress ("0x1" ), 1 )
856+ if err == nil {
857+ t .Error ("expected error to be propagated from storage" )
858+ }
859+ }
860+
861+ func TestHasSubmittedSpecificBlockBalances_NotSubmitted (t * testing.T ) {
862+ storage := & stubStorage {values : map [[32 ]byte ]bool {}}
863+ task := & submitNetworkBalances {storage : storage }
864+
865+ b := newNetworkBalances ()
866+ b .ClampedTotalBalanceWei = ethToWei (500 )
867+ b .TotalStaking = ethToWei (300 )
868+ b .SlotTimestamp = 1_234_567_890
869+
870+ got , err := task .hasSubmittedSpecificBlockBalances (common .HexToAddress ("0xabcd" ), 99 , b )
871+ if err != nil {
872+ t .Fatalf ("unexpected error: %v" , err )
873+ }
874+ if got {
875+ t .Error ("expected false when specific balances have not been submitted" )
876+ }
877+ }
878+
879+ func TestHasSubmittedSpecificBlockBalances_Submitted (t * testing.T ) {
880+ nodeAddr := common .HexToAddress ("0xabcd" )
881+ blockNumber := uint64 (99 )
882+
883+ b := newNetworkBalances ()
884+ b .ClampedTotalBalanceWei = ethToWei (500 )
885+ b .TotalStaking = ethToWei (300 )
886+ b .SlotTimestamp = 1_234_567_890
887+
888+ key := specificBlockBalancesKey (nodeAddr , blockNumber , b )
889+ storage := & stubStorage {values : map [[32 ]byte ]bool {key : true }}
890+ task := & submitNetworkBalances {storage : storage }
891+
892+ got , err := task .hasSubmittedSpecificBlockBalances (nodeAddr , blockNumber , b )
893+ if err != nil {
894+ t .Fatalf ("unexpected error: %v" , err )
895+ }
896+ if ! got {
897+ t .Error ("expected true when the exact same balances were previously submitted" )
898+ }
899+ }
900+
901+ func TestHasSubmittedSpecificBlockBalances_DifferentValues (t * testing.T ) {
902+ nodeAddr := common .HexToAddress ("0xabcd" )
903+ blockNumber := uint64 (99 )
904+
905+ submitted := newNetworkBalances ()
906+ submitted .ClampedTotalBalanceWei = ethToWei (500 )
907+ submitted .TotalStaking = ethToWei (300 )
908+ submitted .RETHSupply = ethToWei (400 )
909+ submitted .SlotTimestamp = 1_000
910+
911+ // Store the specific key for the original submitted values.
912+ submittedKey := specificBlockBalancesKey (nodeAddr , blockNumber , submitted )
913+ storage := & stubStorage {values : map [[32 ]byte ]bool {submittedKey : true }}
914+ task := & submitNetworkBalances {storage : storage }
915+
916+ // Confirm the original values return true (sanity check).
917+ gotOriginal , err := task .hasSubmittedSpecificBlockBalances (nodeAddr , blockNumber , submitted )
918+ if err != nil {
919+ t .Fatalf ("unexpected error on original: %v" , err )
920+ }
921+ if ! gotOriginal {
922+ t .Fatal ("sanity check failed: expected true for the originally submitted values" )
923+ }
924+
925+ // Change TotalStaking → key no longer matches.
926+ altered := submitted
927+ altered .TotalStaking = new (big.Int ).Set (ethToWei (301 ))
928+
929+ got , err := task .hasSubmittedSpecificBlockBalances (nodeAddr , blockNumber , altered )
930+ if err != nil {
931+ t .Fatalf ("unexpected error: %v" , err )
932+ }
933+ if got {
934+ t .Error ("expected false when TotalStaking differs from what was submitted" )
935+ }
936+ }
937+
938+ // TestHasSubmittedSpecificVsBlock verifies that the two functions use distinct
939+ // storage keys: setting the block-level key does not satisfy the specific check.
940+ func TestHasSubmittedSpecificVsBlock (t * testing.T ) {
941+ nodeAddr := common .HexToAddress ("0x5678" )
942+ blockNumber := uint64 (42 )
943+
944+ b := newNetworkBalances ()
945+ b .ClampedTotalBalanceWei = ethToWei (100 )
946+ b .TotalStaking = ethToWei (50 )
947+ b .SlotTimestamp = 9999
948+
949+ // Only set the block-level key.
950+ blockKey := blockBalancesKey (nodeAddr , blockNumber )
951+ storage := & stubStorage {values : map [[32 ]byte ]bool {blockKey : true }}
952+ task := & submitNetworkBalances {storage : storage }
953+
954+ hasBlock , err := task .hasSubmittedBlockBalances (nodeAddr , blockNumber )
955+ if err != nil {
956+ t .Fatalf ("unexpected error: %v" , err )
957+ }
958+ hasSpecific , err := task .hasSubmittedSpecificBlockBalances (nodeAddr , blockNumber , b )
959+ if err != nil {
960+ t .Fatalf ("unexpected error: %v" , err )
961+ }
962+
963+ if ! hasBlock {
964+ t .Error ("expected hasSubmittedBlockBalances=true" )
965+ }
966+ if hasSpecific {
967+ t .Error ("expected hasSubmittedSpecificBlockBalances=false (key is different from block-level key)" )
968+ }
969+ }
970+
971+ func TestHasSubmittedSpecificBlockBalances_PropagatesError (t * testing.T ) {
972+ storage := & stubStorage {err : fmt .Errorf ("storage unavailable" )}
973+ task := & submitNetworkBalances {storage : storage }
974+
975+ b := newNetworkBalances ()
976+ b .ClampedTotalBalanceWei = big .NewInt (1 )
977+ b .TotalStaking = big .NewInt (0 )
978+
979+ _ , err := task .hasSubmittedSpecificBlockBalances (common .HexToAddress ("0x1" ), 1 , b )
980+ if err == nil {
981+ t .Error ("expected error to be propagated from storage" )
982+ }
983+ }
0 commit comments