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