diff --git a/cmd/erigon-cl/core/transition/process_slots.go b/cmd/erigon-cl/core/transition/process_slots.go index 83afc3608..520e3935f 100644 --- a/cmd/erigon-cl/core/transition/process_slots.go +++ b/cmd/erigon-cl/core/transition/process_slots.go @@ -3,6 +3,7 @@ package transition import ( "fmt" + "github.com/Giulio2002/bls" "github.com/ledgerwatch/erigon/cl/cltypes" ) @@ -39,3 +40,12 @@ func (s *StateTransistor) processSlots(state *cltypes.BeaconState, slot uint64) } return nil } + +func (s *StateTransistor) verifyBlockSignature(state *cltypes.BeaconState, block *cltypes.SignedBeaconBlockBellatrix) (bool, error) { + proposer := state.Validators[block.Block.ProposerIndex] + signing_root, err := block.Block.Body.HashTreeRoot() + if err != nil { + return false, err + } + return bls.Verify(block.Signature[:], signing_root[:], proposer.PublicKey[:]) +} diff --git a/cmd/erigon-cl/core/transition/process_slots_test.go b/cmd/erigon-cl/core/transition/process_slots_test.go index 803e43d3a..9ec4e1d44 100644 --- a/cmd/erigon-cl/core/transition/process_slots_test.go +++ b/cmd/erigon-cl/core/transition/process_slots_test.go @@ -24,8 +24,34 @@ var ( blockHash43 = "3ff92b54cba8067044f6b6ca0a69c7a6344154de2a38742e7a89b1057877fffa" stateHash44 = "81954d95a6452e516c076f3254424cac99ae3e8c757f33d8aacb97fd8ef02864" blockHash44 = "3ff92b54cba8067044f6b6ca0a69c7a6344154de2a38742e7a89b1057877fffa" + + testPubKey = [48]byte{152, 250, 212, 202, 139, 152, 8, 45, 224, 234, 128, 186, 142, 67, 172, 78, 124, 69, 173, 39, 48, 98, 75, 146, 244, 131, 55, 15, 138, 170, 246, 81, 77, 88, 244, 114, 1, 47, 123, 123, 55, 174, 58, 139, 90, 249, 237, 19} + testSignature = [96]byte{141, 154, 97, 227, 33, 202, 245, 163, 252, 75, 124, 240, 197, 188, 117, 88, 146, 35, 171, 19, 247, 222, 208, 78, 160, 135, 37, 246, 251, 1, 170, 160, 121, 83, 11, 146, 207, 100, 82, 101, 243, 131, 17, 142, 201, 231, 170, 116, 5, 62, 23, 250, 166, 178, 120, 64, 214, 70, 122, 203, 30, 156, 153, 12, 69, 247, 193, 208, 73, 4, 245, 70, 97, 67, 42, 217, 30, 98, 191, 21, 190, 47, 168, 218, 36, 52, 59, 238, 88, 14, 100, 105, 16, 231, 157, 172} + badSignature = [96]byte{182, 82, 244, 116, 233, 59, 56, 251, 52, 194, 122, 255, 161, 96, 204, 165, 43, 97, 19, 48, 130, 187, 17, 200, 223, 62, 114, 194, 225, 19, 242, 174, 224, 24, 188, 83, 118, 45, 23, 192, 205, 200, 47, 165, 212, 35, 193, 189, 10, 165, 161, 72, 81, 250, 195, 186, 174, 197, 26, 208, 165, 254, 31, 214, 135, 140, 129, 47, 211, 59, 87, 136, 55, 242, 93, 149, 128, 30, 84, 126, 182, 157, 70, 90, 68, 113, 7, 92, 70, 230, 164, 54, 120, 16, 180, 151} + testValidator = &cltypes.Validator{ + PublicKey: testPubKey, + } ) +func getTestBeaconBlock() *cltypes.SignedBeaconBlockBellatrix { + return &cltypes.SignedBeaconBlockBellatrix{ + Block: &cltypes.BeaconBlockBellatrix{ + ProposerIndex: 0, + Body: &cltypes.BeaconBodyBellatrix{ + Graffiti: make([]byte, 32), + SyncAggregate: &cltypes.SyncAggregate{ + SyncCommiteeBits: make([]byte, 64), + }, + ExecutionPayload: &cltypes.ExecutionPayload{ + LogsBloom: make([]byte, 256), + BaseFeePerGas: make([]byte, 32), + }, + }, + }, + Signature: testSignature, + } +} + func getTestBeaconState() *cltypes.BeaconState { return &cltypes.BeaconState{ BlockRoots: make([][32]byte, 8192), @@ -54,6 +80,12 @@ func getTestBeaconState() *cltypes.BeaconState { } } +func getTestBeaconStateWithValidator() *cltypes.BeaconState { + res := getTestBeaconState() + res.Validators = append(res.Validators, testValidator) + return res +} + func prepareNextBeaconState(t *testing.T, slots []uint64, stateHashs, blockHashs []string) *cltypes.BeaconState { nextState := getTestBeaconState() // Set slot to initial index. @@ -217,3 +249,62 @@ func TestProcessSlots(t *testing.T) { }) } } + +func TestVerifyBlockSignature(t *testing.T) { + badSigBlock := getTestBeaconBlock() + badSigBlock.Signature = badSignature + testCases := []struct { + description string + state *cltypes.BeaconState + block *cltypes.SignedBeaconBlockBellatrix + wantValid bool + wantErr bool + }{ + { + description: "success", + state: getTestBeaconStateWithValidator(), + block: getTestBeaconBlock(), + wantErr: false, + wantValid: true, + }, + { + description: "failure_empty_block", + state: getTestBeaconStateWithValidator(), + block: &cltypes.SignedBeaconBlockBellatrix{ + Block: &cltypes.BeaconBlockBellatrix{ + Body: &cltypes.BeaconBodyBellatrix{}, + }, + }, + wantErr: true, + }, + { + description: "failure_bad_signature", + state: getTestBeaconStateWithValidator(), + block: badSigBlock, + wantErr: false, + wantValid: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + s := New(tc.state, testBeaconConfig, nil) + valid, err := s.verifyBlockSignature(tc.state, tc.block) + if tc.wantErr { + if err == nil { + t.Errorf("unexpected success, wanted error") + } + return + } + // Non-failure case. + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Confirm that validity matches what we expect. + if valid != tc.wantValid { + t.Errorf("unexpected difference in validity: want %v, got %v", tc.wantValid, valid) + } + }) + } +}