mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
New struct in consensus/XDPoS/utils/types.go, util functions, and test. (#14)
* define vote, timeout, sync info, qc, tc, extra fields in types.go, add test in types_test.go * add json tag in types.go, refine encoder decoder of extra fields * refactor types.go utils.go * re-write types, comments * add Hash SigHash for types, and tests * define Round type * remove unnecessary logs
This commit is contained in:
parent
7808840be0
commit
4453a1e257
3 changed files with 160 additions and 0 deletions
|
|
@ -57,3 +57,50 @@ type PublicApiSnapshot struct {
|
||||||
Votes []*clique.Vote `json:"votes"` // List of votes cast in chronological order
|
Votes []*clique.Vote `json:"votes"` // List of votes cast in chronological order
|
||||||
Tally map[common.Address]clique.Tally `json:"tally"` // Current vote tally to avoid recalculating
|
Tally map[common.Address]clique.Tally `json:"tally"` // Current vote tally to avoid recalculating
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Round number type in XDPoS 2.0
|
||||||
|
type Round uint64
|
||||||
|
|
||||||
|
// Vote message in XDPoS 2.0
|
||||||
|
type Vote struct {
|
||||||
|
ProposedBlockInfo BlockInfo
|
||||||
|
Signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout message in XDPoS 2.0
|
||||||
|
type Timeout struct {
|
||||||
|
Round Round
|
||||||
|
Signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// BFT Sync Info message in XDPoS 2.0
|
||||||
|
type SyncInfo struct {
|
||||||
|
HighestQuorumCert QuorumCert
|
||||||
|
HighestTimeoutCert TimeoutCert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block Info struct in XDPoS 2.0, used for vote message, etc.
|
||||||
|
type BlockInfo struct {
|
||||||
|
Hash common.Hash
|
||||||
|
Round Round
|
||||||
|
Number *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quorum Certificate struct in XDPoS 2.0
|
||||||
|
type QuorumCert struct {
|
||||||
|
ProposedBlockInfo BlockInfo
|
||||||
|
Signatures [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout Certificate struct in XDPoS 2.0
|
||||||
|
type TimeoutCert struct {
|
||||||
|
Round Round
|
||||||
|
Signatures [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parsed extra fields in block header in XDPoS 2.0 (excluding the version byte)
|
||||||
|
// The version byte (consensus version) is the first byte in header's extra and it's only valid with value >= 2
|
||||||
|
type ExtraFields_v2 struct {
|
||||||
|
Round Round
|
||||||
|
QuorumCert QuorumCert
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package utils
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -149,3 +150,55 @@ func SigHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode XDPoS 2.0 extra fields into bytes
|
||||||
|
func (e *ExtraFields_v2) EncodeToBytes() ([]byte, error) {
|
||||||
|
bytes, err := rlp.EncodeToBytes(e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
versionByte := []byte{2}
|
||||||
|
return append(versionByte, bytes...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
|
||||||
|
func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return fmt.Errorf("extra field is 0 length")
|
||||||
|
}
|
||||||
|
switch b[0] {
|
||||||
|
case 1:
|
||||||
|
return fmt.Errorf("consensus version 1 is not applicable for decoding extra fields")
|
||||||
|
case 2:
|
||||||
|
return rlp.DecodeBytes(b[1:], val)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("consensus version %d is not defined", b[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rlpHash(x interface{}) (h common.Hash) {
|
||||||
|
hw := sha3.NewKeccak256()
|
||||||
|
rlp.Encode(hw, x)
|
||||||
|
hw.Sum(h[:0])
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Vote) Hash() common.Hash {
|
||||||
|
return rlpHash(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Timeout) Hash() common.Hash {
|
||||||
|
return rlpHash(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SyncInfo) Hash() common.Hash {
|
||||||
|
return rlpHash(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VoteSigHash(m *BlockInfo) common.Hash {
|
||||||
|
return rlpHash(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TimeoutSigHash(m *Round) common.Hash {
|
||||||
|
return rlpHash(m)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package utils
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
|
@ -82,3 +83,62 @@ func TestCompareSignersLists(t *testing.T) {
|
||||||
t.Error("Failed with list has only one signer")
|
t.Error("Failed with list has only one signer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toyExtraFields() *ExtraFields_v2 {
|
||||||
|
round := Round(307)
|
||||||
|
blockInfo := BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(1)}
|
||||||
|
signature := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
|
signatures := [][]byte{signature}
|
||||||
|
quorumCert := QuorumCert{ProposedBlockInfo: blockInfo, Signatures: signatures}
|
||||||
|
e := &ExtraFields_v2{Round: round, QuorumCert: quorumCert}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
func TestExtraFieldsEncodeDecode(t *testing.T) {
|
||||||
|
extraFields := toyExtraFields()
|
||||||
|
encoded, err := extraFields.EncodeToBytes()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error when encoding extra fields")
|
||||||
|
}
|
||||||
|
var decoded ExtraFields_v2
|
||||||
|
err = DecodeBytesExtraFields(encoded, &decoded)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error when decoding extra fields")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*extraFields, decoded) {
|
||||||
|
t.Fatalf("Decoded not equal to original extra field, original: %v; decoded: %v", extraFields, decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHashAndSigHash(t *testing.T) {
|
||||||
|
round := Round(307)
|
||||||
|
blockInfo1 := BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(1)}
|
||||||
|
blockInfo2 := BlockInfo{Hash: common.BigToHash(big.NewInt(4095)), Round: round - 1, Number: big.NewInt(1)}
|
||||||
|
signature1 := []byte{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
|
signature2 := []byte{1, 2, 3, 4, 5, 6, 7, 7}
|
||||||
|
signatures1 := [][]byte{signature1}
|
||||||
|
quorumCert1 := QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures1}
|
||||||
|
signatures2 := [][]byte{signature2}
|
||||||
|
quorumCert2 := QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures2}
|
||||||
|
vote1 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature1}
|
||||||
|
vote2 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature2}
|
||||||
|
if vote1.Hash() == vote2.Hash() {
|
||||||
|
t.Fatalf("Hash of two votes shouldn't equal")
|
||||||
|
}
|
||||||
|
timeout1 := Timeout{Round: 10, Signature: signature1}
|
||||||
|
timeout2 := Timeout{Round: 10, Signature: signature2}
|
||||||
|
if timeout1.Hash() == timeout2.Hash() {
|
||||||
|
t.Fatalf("Hash of two timeouts shouldn't equal")
|
||||||
|
}
|
||||||
|
syncInfo1 := SyncInfo{HighestQuorumCert: quorumCert1}
|
||||||
|
syncInfo2 := SyncInfo{HighestQuorumCert: quorumCert2}
|
||||||
|
if syncInfo1.Hash() == syncInfo2.Hash() {
|
||||||
|
t.Fatalf("Hash of two sync info shouldn't equal")
|
||||||
|
}
|
||||||
|
if VoteSigHash(&blockInfo1) == VoteSigHash(&blockInfo2) {
|
||||||
|
t.Fatalf("SigHash of two block info shouldn't equal")
|
||||||
|
}
|
||||||
|
round2 := Round(999)
|
||||||
|
if TimeoutSigHash(&round) == TimeoutSigHash(&round2) {
|
||||||
|
t.Fatalf("SigHash of two round shouldn't equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue