github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/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 "math/big" 23 "strings" 24 "testing" 25 "time" 26 27 bls "github.com/celo-org/bls-zexe/go" 28 "github.com/ethereum/go-ethereum/accounts" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/consensus/istanbul" 31 "github.com/ethereum/go-ethereum/consensus/istanbul/validator" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/crypto" 34 blscrypto "github.com/ethereum/go-ethereum/crypto/bls" 35 ) 36 37 func TestSign(t *testing.T) { 38 b := newBackend() 39 data := []byte("Here is a string....") 40 sig, err := b.Sign(data) 41 if err != nil { 42 t.Errorf("error mismatch: have %v, want nil", err) 43 } 44 //Check signature recover 45 hashData := crypto.Keccak256([]byte(data)) 46 pubkey, _ := crypto.Ecrecover(hashData, sig) 47 var signer common.Address 48 copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) 49 if signer != getAddress() { 50 t.Errorf("address mismatch: have %v, want %s", signer.Hex(), getAddress().Hex()) 51 } 52 } 53 54 func TestCheckSignature(t *testing.T) { 55 key, _ := generatePrivateKey() 56 data := []byte("Here is a string....") 57 hashData := crypto.Keccak256([]byte(data)) 58 sig, _ := crypto.Sign(hashData, key) 59 b := newBackend() 60 a := getAddress() 61 err := b.CheckSignature(data, a, sig) 62 if err != nil { 63 t.Errorf("error mismatch: have %v, want nil", err) 64 } 65 a = getInvalidAddress() 66 err = b.CheckSignature(data, a, sig) 67 if err != errInvalidSignature { 68 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 69 } 70 } 71 72 func TestCheckValidatorSignature(t *testing.T) { 73 vset, keys := newTestValidatorSet(5) 74 75 // 1. Positive test: sign with validator's key should succeed 76 data := []byte("dummy data") 77 hashData := crypto.Keccak256([]byte(data)) 78 for i, k := range keys { 79 // Sign 80 sig, err := crypto.Sign(hashData, k) 81 if err != nil { 82 t.Errorf("error mismatch: have %v, want nil", err) 83 } 84 // CheckValidatorSignature should succeed 85 addr, err := istanbul.CheckValidatorSignature(vset, data, sig) 86 if err != nil { 87 t.Errorf("error mismatch: have %v, want nil", err) 88 } 89 validator := vset.GetByIndex(uint64(i)) 90 if addr != validator.Address() { 91 t.Errorf("validator address mismatch: have %v, want %v", addr, validator.Address()) 92 } 93 } 94 95 // 2. Negative test: sign with any key other than validator's key should return error 96 key, err := crypto.GenerateKey() 97 if err != nil { 98 t.Errorf("error mismatch: have %v, want nil", err) 99 } 100 // Sign 101 sig, err := crypto.Sign(hashData, key) 102 if err != nil { 103 t.Errorf("error mismatch: have %v, want nil", err) 104 } 105 106 // CheckValidatorSignature should return ErrUnauthorizedAddress 107 addr, err := istanbul.CheckValidatorSignature(vset, data, sig) 108 if err != istanbul.ErrUnauthorizedAddress { 109 t.Errorf("error mismatch: have %v, want %v", err, istanbul.ErrUnauthorizedAddress) 110 } 111 emptyAddr := common.Address{} 112 if addr != emptyAddr { 113 t.Errorf("address mismatch: have %v, want %v", addr, emptyAddr) 114 } 115 } 116 117 func TestCommit(t *testing.T) { 118 backend := newBackend() 119 120 commitCh := make(chan *types.Block) 121 // Case: it's a proposer, so the backend.commit will receive channel result from backend.Commit function 122 testCases := []struct { 123 expectedErr error 124 expectedSignature []byte 125 expectedBlock func() *types.Block 126 }{ 127 { 128 // normal case 129 nil, 130 make([]byte, types.IstanbulExtraBlsSignature), 131 func() *types.Block { 132 chain, engine := newBlockChain(1, true) 133 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 134 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 135 return expectedBlock 136 }, 137 }, 138 { 139 // invalid signature 140 errInvalidAggregatedSeal, 141 nil, 142 func() *types.Block { 143 chain, engine := newBlockChain(1, true) 144 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 145 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 146 return expectedBlock 147 }, 148 }, 149 } 150 151 for _, test := range testCases { 152 expBlock := test.expectedBlock() 153 go func() { 154 result := <-backend.commitCh 155 commitCh <- result 156 }() 157 158 backend.proposedBlockHash = expBlock.Hash() 159 if err := backend.Commit(expBlock, types.IstanbulAggregatedSeal{Round: big.NewInt(0), Bitmap: big.NewInt(0), Signature: test.expectedSignature}, types.IstanbulEpochValidatorSetSeal{Signature: nil}); err != nil { 160 if err != test.expectedErr { 161 t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr) 162 } 163 } 164 165 if test.expectedErr == nil { 166 // to avoid race condition is occurred by goroutine 167 select { 168 case result := <-commitCh: 169 if result.Hash() != expBlock.Hash() { 170 t.Errorf("hash mismatch: have %v, want %v", result.Hash(), expBlock.Hash()) 171 } 172 case <-time.After(10 * time.Second): 173 t.Fatal("timeout") 174 } 175 } 176 } 177 } 178 179 func TestGetProposer(t *testing.T) { 180 chain, engine := newBlockChain(1, true) 181 block := makeBlock(chain, engine, chain.Genesis()) 182 chain.InsertChain(types.Blocks{block}) 183 expected := engine.AuthorForBlock(1) 184 actual := engine.Address() 185 if actual != expected { 186 t.Errorf("proposer mismatch: have %v, want %v, currentblock: %v", actual.Hex(), expected.Hex(), chain.CurrentBlock().Number()) 187 } 188 } 189 190 /** 191 * SimpleBackend 192 * Private key: bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1 193 * Public key: 04a2bfb0f7da9e1b9c0c64e14f87e8fb82eb0144e97c25fe3a977a921041a50976984d18257d2495e7bfd3d4b280220217f429287d25ecdf2b0d7c0f7aae9aa624 194 * Address: 0x70524d664ffe731100208a0154e556f9bb679ae6 195 */ 196 func getAddress() common.Address { 197 return common.HexToAddress("0x70524d664ffe731100208a0154e556f9bb679ae6") 198 } 199 200 func getInvalidAddress() common.Address { 201 return common.HexToAddress("0xc63597005f0da07a9ea85b5052a77c3b0261bdca") 202 } 203 204 func generatePrivateKey() (*ecdsa.PrivateKey, error) { 205 key := "bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1" 206 return crypto.HexToECDSA(key) 207 } 208 209 func generateInvalidPrivateKey() (*ecdsa.PrivateKey, error) { 210 key := "1049c0e0b99eeea3465a1e83a52900dc27c652f39abb3aed3b868dee68ff1d2c" 211 return crypto.HexToECDSA(key) 212 } 213 214 func newTestValidatorSet(n int) (istanbul.ValidatorSet, []*ecdsa.PrivateKey) { 215 // generate validators 216 keys := make(Keys, n) 217 validators := make([]istanbul.ValidatorData, n) 218 for i := 0; i < n; i++ { 219 privateKey, _ := crypto.GenerateKey() 220 blsPrivateKey, _ := blscrypto.ECDSAToBLS(privateKey) 221 blsPublicKey, _ := blscrypto.PrivateToPublic(blsPrivateKey) 222 keys[i] = privateKey 223 validators[i] = istanbul.ValidatorData{ 224 crypto.PubkeyToAddress(privateKey.PublicKey), 225 blsPublicKey, 226 } 227 } 228 vset := validator.NewSet(validators) 229 return vset, keys 230 } 231 232 type Keys []*ecdsa.PrivateKey 233 234 func (slice Keys) Len() int { 235 return len(slice) 236 } 237 238 func (slice Keys) Less(i, j int) bool { 239 return strings.Compare(crypto.PubkeyToAddress(slice[i].PublicKey).String(), crypto.PubkeyToAddress(slice[j].PublicKey).String()) < 0 240 } 241 242 func (slice Keys) Swap(i, j int) { 243 slice[i], slice[j] = slice[j], slice[i] 244 } 245 246 func signerFn(_ accounts.Account, data []byte) ([]byte, error) { 247 key, _ := generatePrivateKey() 248 return crypto.Sign(data, key) 249 } 250 251 func signerBLSHashFn(_ accounts.Account, data []byte) (blscrypto.SerializedSignature, error) { 252 key, _ := generatePrivateKey() 253 privateKeyBytes, err := blscrypto.ECDSAToBLS(key) 254 if err != nil { 255 return blscrypto.SerializedSignature{}, err 256 } 257 258 privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) 259 if err != nil { 260 return blscrypto.SerializedSignature{}, err 261 } 262 defer privateKey.Destroy() 263 264 signature, err := privateKey.SignMessage(data, []byte{}, false) 265 if err != nil { 266 return blscrypto.SerializedSignature{}, err 267 } 268 defer signature.Destroy() 269 signatureBytes, err := signature.Serialize() 270 if err != nil { 271 return blscrypto.SerializedSignature{}, err 272 } 273 274 return blscrypto.SerializedSignatureFromBytes(signatureBytes) 275 } 276 277 func signerBLSMessageFn(_ accounts.Account, data []byte, extraData []byte) (blscrypto.SerializedSignature, error) { 278 key, _ := generatePrivateKey() 279 privateKeyBytes, err := blscrypto.ECDSAToBLS(key) 280 if err != nil { 281 return blscrypto.SerializedSignature{}, err 282 } 283 284 privateKey, err := bls.DeserializePrivateKey(privateKeyBytes) 285 if err != nil { 286 return blscrypto.SerializedSignature{}, err 287 } 288 defer privateKey.Destroy() 289 290 signature, err := privateKey.SignMessage(data, extraData, true) 291 if err != nil { 292 return blscrypto.SerializedSignature{}, err 293 } 294 defer signature.Destroy() 295 signatureBytes, err := signature.Serialize() 296 if err != nil { 297 return blscrypto.SerializedSignature{}, err 298 } 299 300 return blscrypto.SerializedSignatureFromBytes(signatureBytes) 301 } 302 303 func newBackend() (b *Backend) { 304 _, b = newBlockChain(4, true) 305 306 key, _ := generatePrivateKey() 307 b.Authorize(crypto.PubkeyToAddress(key.PublicKey), signerFn, signerBLSHashFn, signerBLSMessageFn) 308 return 309 } 310 311 func signerFnInvalid(_ accounts.Account, data []byte) ([]byte, error) { 312 key, _ := generateInvalidPrivateKey() 313 return crypto.Sign(data, key) 314 }