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  */