github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/raft/minter_test.go (about) 1 package raft 2 3 import ( 4 "errors" 5 "fmt" 6 "math/big" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/coreos/etcd/raft/raftpb" 12 "github.com/deckarep/golang-set" 13 "github.com/ethereum/go-ethereum/p2p/enode" 14 15 "github.com/ethereum/go-ethereum/common" 16 "github.com/ethereum/go-ethereum/common/hexutil" 17 "github.com/ethereum/go-ethereum/core/types" 18 "github.com/ethereum/go-ethereum/crypto" 19 "github.com/ethereum/go-ethereum/node" 20 "github.com/ethereum/go-ethereum/rlp" 21 ) 22 23 const TEST_URL = "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404" 24 25 func TestSignHeader(t *testing.T) { 26 //create only what we need to test the seal 27 var testRaftId uint16 = 5 28 config := &node.Config{Name: "unit-test", DataDir: ""} 29 30 nodeKey := config.NodeKey() 31 32 raftProtocolManager := &ProtocolManager{raftId: testRaftId} 33 raftService := &RaftService{nodeKey: nodeKey, raftProtocolManager: raftProtocolManager} 34 minter := minter{eth: raftService} 35 36 //create some fake header to sign 37 fakeParentHash := common.HexToHash("0xc2c1dc1be8054808c69e06137429899d") 38 39 header := &types.Header{ 40 ParentHash: fakeParentHash, 41 Number: big.NewInt(1), 42 Difficulty: big.NewInt(1), 43 GasLimit: uint64(0), 44 GasUsed: uint64(0), 45 Coinbase: minter.coinbase, 46 Time: big.NewInt(time.Now().UnixNano()), 47 } 48 49 headerHash := header.Hash() 50 extraDataBytes := minter.buildExtraSeal(headerHash) 51 var seal *extraSeal 52 err := rlp.DecodeBytes(extraDataBytes[:], &seal) 53 if err != nil { 54 t.Fatalf("Unable to decode seal: %s", err.Error()) 55 } 56 57 // Check raftId 58 sealRaftId, err := hexutil.DecodeUint64("0x" + string(seal.RaftId)) //add the 0x prefix 59 if err != nil { 60 t.Errorf("Unable to get RaftId: %s", err.Error()) 61 } 62 if sealRaftId != uint64(testRaftId) { 63 t.Errorf("RaftID does not match. Expected: %d, Actual: %d", testRaftId, sealRaftId) 64 } 65 66 //Identify who signed it 67 sig := seal.Signature 68 pubKey, err := crypto.SigToPub(headerHash.Bytes(), sig) 69 if err != nil { 70 t.Fatalf("Unable to get public key from signature: %s", err.Error()) 71 } 72 73 //Compare derived public key to original public key 74 if pubKey.X.Cmp(nodeKey.X) != 0 { 75 t.Errorf("Signature incorrect!") 76 } 77 78 } 79 80 func TestAddLearner_whenTypical(t *testing.T) { 81 82 raftService := newTestRaftService(t, 1, []uint64{1}, []uint64{}) 83 84 propPeer := func() { 85 raftid, err := raftService.raftProtocolManager.ProposeNewPeer(TEST_URL, true) 86 if err != nil { 87 t.Errorf("propose new peer failed %v\n", err) 88 } 89 if raftid != raftService.raftProtocolManager.raftId+1 { 90 t.Errorf("1. wrong raft id. expected %d got %d\n", raftService.raftProtocolManager.raftId+1, raftid) 91 } 92 } 93 go propPeer() 94 select { 95 case confChange := <-raftService.raftProtocolManager.confChangeProposalC: 96 if confChange.Type != raftpb.ConfChangeAddLearnerNode { 97 t.Errorf("expected ConfChangeAddLearnerNode but got %s", confChange.Type.String()) 98 } 99 if uint16(confChange.NodeID) != raftService.raftProtocolManager.raftId+1 { 100 t.Errorf("2. wrong raft id. expected %d got %d\n", raftService.raftProtocolManager.raftId+1, uint16(confChange.NodeID)) 101 } 102 case <-time.After(time.Millisecond * 200): 103 t.Errorf("add learner conf change not recieved") 104 } 105 } 106 107 func TestPromoteLearnerToPeer_whenTypical(t *testing.T) { 108 learnerRaftId := uint16(3) 109 raftService := newTestRaftService(t, 2, []uint64{2}, []uint64{uint64(learnerRaftId)}) 110 promoteToPeer := func() { 111 ok, err := raftService.raftProtocolManager.PromoteToPeer(learnerRaftId) 112 if err != nil || !ok { 113 t.Errorf("promote learner to peer failed %v\n", err) 114 } 115 } 116 go promoteToPeer() 117 select { 118 case confChange := <-raftService.raftProtocolManager.confChangeProposalC: 119 if confChange.Type != raftpb.ConfChangeAddNode { 120 t.Errorf("expected ConfChangeAddNode but got %s", confChange.Type.String()) 121 } 122 if uint16(confChange.NodeID) != learnerRaftId { 123 t.Errorf("2. wrong raft id. expected %d got %d\n", learnerRaftId, uint16(confChange.NodeID)) 124 } 125 case <-time.After(time.Millisecond * 200): 126 t.Errorf("add learner conf change not recieved") 127 } 128 } 129 130 func TestAddLearnerOrPeer_fromLearner(t *testing.T) { 131 132 raftService := newTestRaftService(t, 3, []uint64{2}, []uint64{3}) 133 134 _, err := raftService.raftProtocolManager.ProposeNewPeer(TEST_URL, true) 135 136 if err == nil { 137 t.Errorf("learner should not be allowed to add learner or peer") 138 } 139 140 if err != nil && strings.Index(err.Error(), "learner node can't add peer or learner") == -1 { 141 t.Errorf("expect error message: propose new peer failed, got: %v\n", err) 142 } 143 144 _, err = raftService.raftProtocolManager.ProposeNewPeer(TEST_URL, false) 145 146 if err == nil { 147 t.Errorf("learner should not be allowed to add learner or peer") 148 } 149 150 if err != nil && strings.Index(err.Error(), "learner node can't add peer or learner") == -1 { 151 t.Errorf("expect error message: propose new peer failed, got: %v\n", err) 152 } 153 154 } 155 156 func TestPromoteLearnerToPeer_fromLearner(t *testing.T) { 157 learnerRaftId := uint16(3) 158 raftService := newTestRaftService(t, 2, []uint64{1}, []uint64{2, uint64(learnerRaftId)}) 159 160 _, err := raftService.raftProtocolManager.PromoteToPeer(learnerRaftId) 161 162 if err == nil { 163 t.Errorf("learner should not be allowed to promote to peer") 164 } 165 166 if err != nil && strings.Index(err.Error(), "learner node can't promote to peer") == -1 { 167 t.Errorf("expect error message: propose new peer failed, got: %v\n", err) 168 } 169 170 } 171 172 func enodeId(id string, ip string, raftPort int) string { 173 return fmt.Sprintf("enode://%s@%s?discport=0&raftport=%d", id, ip, raftPort) 174 } 175 176 func peerList(url string) (error, []*enode.Node) { 177 var nodes []*enode.Node 178 node, err := enode.ParseV4(url) 179 if err != nil { 180 return errors.New(fmt.Sprintf("Node URL %s: %v\n", url, err)), nil 181 } 182 nodes = append(nodes, node) 183 return nil, nodes 184 } 185 186 func newTestRaftService(t *testing.T, raftId uint16, nodes []uint64, learners []uint64) *RaftService { 187 //create only what we need to test add learner node 188 config := &node.Config{Name: "unit-test", DataDir: ""} 189 nodeKey := config.NodeKey() 190 enodeIdStr := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]) 191 url := enodeId(enodeIdStr, "127.0.0.1:21001", 50401) 192 err, peers := peerList(url) 193 if err != nil { 194 t.Errorf("getting peers failed %v", err) 195 } 196 raftProtocolManager := &ProtocolManager{ 197 raftId: raftId, 198 bootstrapNodes: peers, 199 confChangeProposalC: make(chan raftpb.ConfChange), 200 removedPeers: mapset.NewSet(), 201 confState: raftpb.ConfState{Nodes: nodes, Learners: learners}, 202 } 203 raftService := &RaftService{nodeKey: nodeKey, raftProtocolManager: raftProtocolManager} 204 return raftService 205 }