github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/backend/backend_test.go (about) 1 package backend 2 /* 3 4 import ( 5 "bytes" 6 "crypto/ecdsa" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/quickchainproject/quickchain/common" 13 "github.com/quickchainproject/quickchain/consensus/dbft" 14 "github.com/quickchainproject/quickchain/consensus/dbft/validator" 15 "github.com/quickchainproject/quickchain/core/types" 16 "github.com/quickchainproject/quickchain/crypto" 17 ) 18 19 func TestSign(t *testing.T) { 20 b := newBackend() 21 data := []byte("Here is a string....") 22 sig, err := b.Sign(data) 23 if err != nil { 24 t.Errorf("error mismatch: have %v, want nil", err) 25 } 26 //Check signature recover 27 hashData := crypto.Keccak256([]byte(data)) 28 pubkey, _ := crypto.Ecrecover(hashData, sig) 29 var signer common.Address 30 copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) 31 if signer != getAddress() { 32 t.Errorf("address mismatch: have %v, want %s", signer.Hex(), getAddress().Hex()) 33 } 34 } 35 36 func TestCheckSignature(t *testing.T) { 37 key, _ := generatePrivateKey() 38 data := []byte("Here is a string....") 39 hashData := crypto.Keccak256([]byte(data)) 40 sig, _ := crypto.Sign(hashData, key) 41 b := newBackend() 42 a := getAddress() 43 err := b.CheckSignature(data, a, sig) 44 if err != nil { 45 t.Errorf("error mismatch: have %v, want nil", err) 46 } 47 a = getInvalidAddress() 48 err = b.CheckSignature(data, a, sig) 49 if err != errInvalidSignature { 50 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 51 } 52 } 53 54 func TestCheckValidatorSignature(t *testing.T) { 55 vset, keys := newTestValidatorSet(5) 56 57 // 1. Positive test: sign with validator's key should succeed 58 data := []byte("dummy data") 59 hashData := crypto.Keccak256([]byte(data)) 60 for i, k := range keys { 61 // Sign 62 sig, err := crypto.Sign(hashData, k) 63 if err != nil { 64 t.Errorf("error mismatch: have %v, want nil", err) 65 } 66 // CheckValidatorSignature should succeed 67 addr, err := bft.CheckValidatorSignature(vset, data, sig) 68 if err != nil { 69 t.Errorf("error mismatch: have %v, want nil", err) 70 } 71 validator := vset.GetByIndex(uint64(i)) 72 if addr != validator.Address() { 73 t.Errorf("validator address mismatch: have %v, want %v", addr, validator.Address()) 74 } 75 } 76 77 // 2. Negative test: sign with any key other than validator's key should return error 78 key, err := crypto.GenerateKey() 79 if err != nil { 80 t.Errorf("error mismatch: have %v, want nil", err) 81 } 82 // Sign 83 sig, err := crypto.Sign(hashData, key) 84 if err != nil { 85 t.Errorf("error mismatch: have %v, want nil", err) 86 } 87 88 // CheckValidatorSignature should return ErrUnauthorizedAddress 89 addr, err := bft.CheckValidatorSignature(vset, data, sig) 90 if err != bft.ErrUnauthorizedAddress { 91 t.Errorf("error mismatch: have %v, want %v", err, bft.ErrUnauthorizedAddress) 92 } 93 emptyAddr := common.Address{} 94 if addr != emptyAddr { 95 t.Errorf("address mismatch: have %v, want %v", addr, emptyAddr) 96 } 97 } 98 99 func TestCommit(t *testing.T) { 100 backend := newBackend() 101 102 commitCh := make(chan *types.Block) 103 // Case: it's a proposer, so the backend.commit will receive channel result from backend.Commit function 104 testCases := []struct { 105 expectedErr error 106 expectedSignature [][]byte 107 expectedBlock func() *types.Block 108 }{ 109 { 110 // normal case 111 nil, 112 [][]byte{append([]byte{1}, bytes.Repeat([]byte{0x00}, types.BFTExtraSeal-1)...)}, 113 func() *types.Block { 114 chain, engine := newBlockChain(1) 115 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 116 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 117 return expectedBlock 118 }, 119 }, 120 { 121 // invalid signature 122 errInvalidCommittedSeals, 123 nil, 124 func() *types.Block { 125 chain, engine := newBlockChain(1) 126 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 127 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 128 return expectedBlock 129 }, 130 }, 131 } 132 133 for _, test := range testCases { 134 expBlock := test.expectedBlock() 135 go func() { 136 select { 137 case result := <-backend.commitCh: 138 commitCh <- result 139 return 140 } 141 }() 142 143 backend.proposedBlockHash = expBlock.Hash() 144 if err := backend.Commit(expBlock, test.expectedSignature); err != nil { 145 if err != test.expectedErr { 146 t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr) 147 } 148 } 149 150 if test.expectedErr == nil { 151 // to avoid race condition is occurred by goroutine 152 select { 153 case result := <-commitCh: 154 if result.Hash() != expBlock.Hash() { 155 t.Errorf("hash mismatch: have %v, want %v", result.Hash(), expBlock.Hash()) 156 } 157 case <-time.After(10 * time.Second): 158 t.Fatal("timeout") 159 } 160 } 161 } 162 } 163 164 func TestGetProposer(t *testing.T) { 165 chain, engine := newBlockChain(1) 166 block := makeBlock(chain, engine, chain.Genesis()) 167 chain.InsertChain(types.Blocks{block}) 168 expected := engine.GetProposer(1) 169 actual := engine.Address() 170 if actual != expected { 171 t.Errorf("proposer mismatch: have %v, want %v", actual.Hex(), expected.Hex()) 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 } 227 */