github.com/ConsenSys/Quorum@v20.10.0+incompatible/consensus/istanbul/backend/backend_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package backend 18 19 import ( 20 "bytes" 21 "crypto/ecdsa" 22 "sort" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/consensus/istanbul" 29 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 ) 33 34 func TestSign(t *testing.T) { 35 b := newBackend() 36 data := []byte("Here is a string....") 37 sig, err := b.Sign(data) 38 if err != nil { 39 t.Errorf("error mismatch: have %v, want nil", err) 40 } 41 //Check signature recover 42 hashData := crypto.Keccak256([]byte(data)) 43 pubkey, _ := crypto.Ecrecover(hashData, sig) 44 var signer common.Address 45 copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) 46 if signer != getAddress() { 47 t.Errorf("address mismatch: have %v, want %s", signer.Hex(), getAddress().Hex()) 48 } 49 } 50 51 func TestCheckSignature(t *testing.T) { 52 key, _ := generatePrivateKey() 53 data := []byte("Here is a string....") 54 hashData := crypto.Keccak256([]byte(data)) 55 sig, _ := crypto.Sign(hashData, key) 56 b := newBackend() 57 a := getAddress() 58 err := b.CheckSignature(data, a, sig) 59 if err != nil { 60 t.Errorf("error mismatch: have %v, want nil", err) 61 } 62 a = getInvalidAddress() 63 err = b.CheckSignature(data, a, sig) 64 if err != errInvalidSignature { 65 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 66 } 67 } 68 69 func TestCheckValidatorSignature(t *testing.T) { 70 vset, keys := newTestValidatorSet(5) 71 72 // 1. Positive test: sign with validator's key should succeed 73 data := []byte("dummy data") 74 hashData := crypto.Keccak256([]byte(data)) 75 for i, k := range keys { 76 // Sign 77 sig, err := crypto.Sign(hashData, k) 78 if err != nil { 79 t.Errorf("error mismatch: have %v, want nil", err) 80 } 81 // CheckValidatorSignature should succeed 82 addr, err := istanbul.CheckValidatorSignature(vset, data, sig) 83 if err != nil { 84 t.Errorf("error mismatch: have %v, want nil", err) 85 } 86 validator := vset.GetByIndex(uint64(i)) 87 if addr != validator.Address() { 88 t.Errorf("validator address mismatch: have %v, want %v", addr, validator.Address()) 89 } 90 } 91 92 // 2. Negative test: sign with any key other than validator's key should return error 93 key, err := crypto.GenerateKey() 94 if err != nil { 95 t.Errorf("error mismatch: have %v, want nil", err) 96 } 97 // Sign 98 sig, err := crypto.Sign(hashData, key) 99 if err != nil { 100 t.Errorf("error mismatch: have %v, want nil", err) 101 } 102 103 // CheckValidatorSignature should return ErrUnauthorizedAddress 104 addr, err := istanbul.CheckValidatorSignature(vset, data, sig) 105 if err != istanbul.ErrUnauthorizedAddress { 106 t.Errorf("error mismatch: have %v, want %v", err, istanbul.ErrUnauthorizedAddress) 107 } 108 emptyAddr := common.Address{} 109 if addr != emptyAddr { 110 t.Errorf("address mismatch: have %v, want %v", addr, emptyAddr) 111 } 112 } 113 114 func TestCommit(t *testing.T) { 115 backend := newBackend() 116 117 commitCh := make(chan *types.Block) 118 // Case: it's a proposer, so the backend.commit will receive channel result from backend.Commit function 119 testCases := []struct { 120 expectedErr error 121 expectedSignature [][]byte 122 expectedBlock func() *types.Block 123 }{ 124 { 125 // normal case 126 nil, 127 [][]byte{append([]byte{1}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-1)...)}, 128 func() *types.Block { 129 chain, engine := newBlockChain(1) 130 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 131 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 132 return expectedBlock 133 }, 134 }, 135 { 136 // invalid signature 137 errInvalidCommittedSeals, 138 nil, 139 func() *types.Block { 140 chain, engine := newBlockChain(1) 141 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 142 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 143 return expectedBlock 144 }, 145 }, 146 } 147 148 for _, test := range testCases { 149 expBlock := test.expectedBlock() 150 go func() { 151 result := <-backend.commitCh 152 commitCh <- result 153 }() 154 155 backend.proposedBlockHash = expBlock.Hash() 156 if err := backend.Commit(expBlock, test.expectedSignature); err != nil { 157 if err != test.expectedErr { 158 t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr) 159 } 160 } 161 162 if test.expectedErr == nil { 163 // to avoid race condition is occurred by goroutine 164 select { 165 case result := <-commitCh: 166 if result.Hash() != expBlock.Hash() { 167 t.Errorf("hash mismatch: have %v, want %v", result.Hash(), expBlock.Hash()) 168 } 169 case <-time.After(10 * time.Second): 170 t.Fatal("timeout") 171 } 172 } 173 } 174 } 175 176 func TestGetProposer(t *testing.T) { 177 chain, engine := newBlockChain(1) 178 block := makeBlock(chain, engine, chain.Genesis()) 179 chain.InsertChain(types.Blocks{block}) 180 expected := engine.GetProposer(1) 181 actual := engine.Address() 182 if actual != expected { 183 t.Errorf("proposer mismatch: have %v, want %v", actual.Hex(), expected.Hex()) 184 } 185 } 186 187 /** 188 * SimpleBackend 189 * Private key: bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1 190 * Public key: 04a2bfb0f7da9e1b9c0c64e14f87e8fb82eb0144e97c25fe3a977a921041a50976984d18257d2495e7bfd3d4b280220217f429287d25ecdf2b0d7c0f7aae9aa624 191 * Address: 0x70524d664ffe731100208a0154e556f9bb679ae6 192 */ 193 func getAddress() common.Address { 194 return common.HexToAddress("0x70524d664ffe731100208a0154e556f9bb679ae6") 195 } 196 197 func getInvalidAddress() common.Address { 198 return common.HexToAddress("0x9535b2e7faaba5288511d89341d94a38063a349b") 199 } 200 201 func generatePrivateKey() (*ecdsa.PrivateKey, error) { 202 key := "bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1" 203 return crypto.HexToECDSA(key) 204 } 205 206 func newTestValidatorSet(n int) (istanbul.ValidatorSet, []*ecdsa.PrivateKey) { 207 // generate validators 208 keys := make(Keys, n) 209 addrs := make([]common.Address, n) 210 for i := 0; i < n; i++ { 211 privateKey, _ := crypto.GenerateKey() 212 keys[i] = privateKey 213 addrs[i] = crypto.PubkeyToAddress(privateKey.PublicKey) 214 } 215 vset := validator.NewSet(addrs, istanbul.RoundRobin) 216 sort.Sort(keys) //Keys need to be sorted by its public key address 217 return vset, keys 218 } 219 220 type Keys []*ecdsa.PrivateKey 221 222 func (slice Keys) Len() int { 223 return len(slice) 224 } 225 226 func (slice Keys) Less(i, j int) bool { 227 return strings.Compare(crypto.PubkeyToAddress(slice[i].PublicKey).String(), crypto.PubkeyToAddress(slice[j].PublicKey).String()) < 0 228 } 229 230 func (slice Keys) Swap(i, j int) { 231 slice[i], slice[j] = slice[j], slice[i] 232 } 233 234 func newBackend() (b *backend) { 235 _, b = newBlockChain(4) 236 key, _ := generatePrivateKey() 237 b.privateKey = key 238 return 239 }