github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/backend/backend_test.go (about) 1 // Copyright 2017 AMIS Technologies 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 "github.com/ethereum/go-ethereum/consensus/podc" 23 "sort" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus/podc/validator" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/log" 33 ) 34 35 func TestSign(t *testing.T) { 36 b, _, _ := newSimpleBackend() 37 data := []byte("Here is a string....") 38 sig, err := b.Sign(data) 39 if err != nil { 40 t.Errorf("error mismatch: have %v, want nil", err) 41 } 42 //Check signature recover 43 hashData := crypto.Keccak256([]byte(data)) 44 pubkey, _ := crypto.Ecrecover(hashData, sig) 45 var signer common.Address 46 copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) 47 if strings.Compare(signer.Hex(), "0x70524d664ffe731100208a0154e556f9bb679ae6") != 0 { 48 t.Errorf("address mismatch: have %v, want 0x70524d664ffe731100208a0154e556f9bb679ae6", signer.Hex()) 49 } 50 } 51 52 func TestCheckSignature(t *testing.T) { 53 key, _ := generatePrivateKey() 54 data := []byte("Here is a string....") 55 hashData := crypto.Keccak256([]byte(data)) 56 sig, _ := crypto.Sign(hashData, key) 57 b, _, _ := newSimpleBackend() 58 a := getAddress() 59 err := b.CheckSignature(data, a, sig) 60 if err != nil { 61 t.Errorf("error mismatch: have %v, want nil", err) 62 } 63 a = getInvalidAddress() 64 err = b.CheckSignature(data, a, sig) 65 if err != errInvalidSignature { 66 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 67 } 68 } 69 70 func TestCheckValidatorSignature(t *testing.T) { 71 _, keys, vset := newSimpleBackend() 72 73 // 1. Positive test: sign with validator's key should succeed 74 data := []byte("dummy data") 75 hashData := crypto.Keccak256([]byte(data)) 76 for i, k := range keys { 77 // Sign 78 sig, err := crypto.Sign(hashData, k) 79 if err != nil { 80 t.Errorf("error mismatch: have %v, want nil", err) 81 } 82 // CheckValidatorSignature should succeed 83 addr, err := podc.CheckValidatorSignature(vset, data, sig) 84 if err != nil { 85 t.Errorf("error mismatch: have %v, want nil", err) 86 } 87 validator := vset.GetByIndex(uint64(i)) 88 if addr != validator.Address() { 89 t.Errorf("validator address mismatch: have %v, want %v", addr, validator.Address()) 90 } 91 } 92 93 // 2. Negative test: sign with any key other than validator's key should return error 94 key, err := crypto.GenerateKey() 95 if err != nil { 96 t.Errorf("error mismatch: have %v, want nil", err) 97 } 98 // Sign 99 sig, err := crypto.Sign(hashData, key) 100 if err != nil { 101 t.Errorf("error mismatch: have %v, want nil", err) 102 } 103 104 // CheckValidatorSignature should return ErrUnauthorizedAddress 105 addr, err := podc.CheckValidatorSignature(vset, data, sig) 106 if err != podc.ErrUnauthorizedAddress { 107 t.Errorf("error mismatch: have %v, want %v", err, podc.ErrUnauthorizedAddress) 108 } 109 emptyAddr := common.Address{} 110 if addr != emptyAddr { 111 t.Errorf("address mismatch: have %v, want %v", addr, emptyAddr) 112 } 113 } 114 115 func TestCommit(t *testing.T) { 116 backend, _, _ := newSimpleBackend() 117 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 append([]byte{1}, bytes.Repeat([]byte{0x00}, types.PoDCExtraSeal-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 for { 152 select { 153 case result := <-backend.commitCh: 154 if result.Hash() != expBlock.Hash() { 155 t.Errorf("hash mismatch: have %v, want %v", result.Hash(), expBlock.Hash()) 156 } 157 return 158 case <-time.After(time.Second): 159 t.Error("unexpected timeout occurs") 160 } 161 } 162 }() 163 164 backend.proposedBlockHash = expBlock.Hash() 165 if err := backend.Commit(expBlock, test.expectedSignature); err != nil { 166 if err != test.expectedErr { 167 t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr) 168 } 169 } 170 } 171 } 172 173 /** 174 * SimpleBackend 175 * Private key: bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1 176 * Public key: 04a2bfb0f7da9e1b9c0c64e14f87e8fb82eb0144e97c25fe3a977a921041a50976984d18257d2495e7bfd3d4b280220217f429287d25ecdf2b0d7c0f7aae9aa624 177 * Address: 0x70524d664ffe731100208a0154e556f9bb679ae6 178 */ 179 func getAddress() common.Address { 180 return common.HexToAddress("0x70524d664ffe731100208a0154e556f9bb679ae6") 181 } 182 183 func getInvalidAddress() common.Address { 184 return common.HexToAddress("0x9535b2e7faaba5288511d89341d94a38063a349b") 185 } 186 187 func generatePrivateKey() (*ecdsa.PrivateKey, error) { 188 key := "bb047e5940b6d83354d9432db7c449ac8fca2248008aaa7271369880f9f11cc1" 189 return crypto.HexToECDSA(key) 190 } 191 192 func newTestValidatorSet(n int) (podc.ValidatorSet, []*ecdsa.PrivateKey) { 193 // generate validators 194 keys := make(Keys, n) 195 addrs := make([]common.Address, n) 196 for i := 0; i < n; i++ { 197 privateKey, _ := crypto.GenerateKey() 198 keys[i] = privateKey 199 addrs[i] = crypto.PubkeyToAddress(privateKey.PublicKey) 200 } 201 vset := validator.NewSet(addrs, podc.RoundRobin) 202 sort.Sort(keys) //Keys need to be sorted by its public key address 203 return vset, keys 204 } 205 206 type Keys []*ecdsa.PrivateKey 207 208 func (slice Keys) Len() int { 209 return len(slice) 210 } 211 212 func (slice Keys) Less(i, j int) bool { 213 return strings.Compare(crypto.PubkeyToAddress(slice[i].PublicKey).String(), crypto.PubkeyToAddress(slice[j].PublicKey).String()) < 0 214 } 215 216 func (slice Keys) Swap(i, j int) { 217 slice[i], slice[j] = slice[j], slice[i] 218 } 219 220 func newSimpleBackend() (backend *simpleBackend, validatorKeys Keys, validatorSet podc.ValidatorSet) { 221 key, _ := generatePrivateKey() 222 validatorSet, validatorKeys = newTestValidatorSet(5) 223 backend = &simpleBackend{ 224 privateKey: key, 225 logger: log.New("backend", "simple"), 226 commitCh: make(chan *types.Block, 1), 227 } 228 return 229 }