aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorSonic <sonic@dexon.org>2018-10-20 16:07:37 +0800
committerWei-Ning Huang <aitjcize@gmail.com>2018-10-20 16:07:37 +0800
commit9fbe8f9e561a64429eb15431782eb4280d0ffbad (patch)
tree035495fdc970b7ad6f2cb1c6b9cc42cbd36526cb /core
parent1f7491df37caf974ffa0c824c4c02a8fe2aafcd9 (diff)
downloaddexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar.gz
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar.bz2
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar.lz
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar.xz
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.tar.zst
dexon-consensus-9fbe8f9e561a64429eb15431782eb4280d0ffbad.zip
core: types: implement rlp.Encoder and rlp.Decoder (#232)
* core: types: implement rlp.Encoder and rlp.Decoder * crypto: dkg: fix PublicKey.Bytes
Diffstat (limited to 'core')
-rw-r--r--core/crypto/dkg/dkg.go98
-rw-r--r--core/crypto/dkg/dkg_test.go25
-rw-r--r--core/types/block.go134
-rw-r--r--core/types/block_test.go23
-rw-r--r--core/types/dkg.go44
-rw-r--r--core/types/dkg_test.go62
6 files changed, 379 insertions, 7 deletions
diff --git a/core/crypto/dkg/dkg.go b/core/crypto/dkg/dkg.go
index 55199a9..8d0e088 100644
--- a/core/crypto/dkg/dkg.go
+++ b/core/crypto/dkg/dkg.go
@@ -20,8 +20,10 @@ package dkg
import (
"encoding/json"
"fmt"
+ "io"
"github.com/Spiderpowa/bls/ffi/go/bls"
+ "github.com/dexon-foundation/dexon/rlp"
"github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/crypto"
@@ -92,6 +94,72 @@ type PublicKeyShares struct {
masterPublicKey []bls.PublicKey
}
+type rlpPublicKeyShares struct {
+ Shares [][]byte
+ ShareIndexK [][]byte
+ ShareIndexV []uint32
+ MasterPublicKey [][]byte
+}
+
+// EncodeRLP implements rlp.Encoder
+func (pubs *PublicKeyShares) EncodeRLP(w io.Writer) error {
+ var rps rlpPublicKeyShares
+ for _, share := range pubs.shares {
+ rps.Shares = append(rps.Shares, share.Serialize())
+ }
+
+ for id, v := range pubs.shareIndex {
+ rps.ShareIndexK = append(rps.ShareIndexK, id.GetLittleEndian())
+ rps.ShareIndexV = append(rps.ShareIndexV, uint32(v))
+ }
+
+ for _, m := range pubs.masterPublicKey {
+ rps.MasterPublicKey = append(rps.MasterPublicKey, m.Serialize())
+ }
+
+ return rlp.Encode(w, rps)
+}
+
+// DecodeRLP implements rlp.Decoder
+func (pubs *PublicKeyShares) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpPublicKeyShares
+ if err := s.Decode(&dec); err != nil {
+ return err
+ }
+
+ if len(dec.ShareIndexK) != len(dec.ShareIndexV) {
+ return fmt.Errorf("invalid shareIndex")
+ }
+
+ ps := NewEmptyPublicKeyShares()
+ for _, share := range dec.Shares {
+ var publicKey PublicKey
+ if err := publicKey.Deserialize(share); err != nil {
+ return err
+ }
+ ps.shares = append(ps.shares, publicKey)
+ }
+
+ for i, k := range dec.ShareIndexK {
+ id, err := BytesID(k)
+ if err != nil {
+ return err
+ }
+ ps.shareIndex[id] = int(dec.ShareIndexV[i])
+ }
+
+ for _, k := range dec.MasterPublicKey {
+ var key bls.PublicKey
+ if err := key.Deserialize(k); err != nil {
+ return err
+ }
+ ps.masterPublicKey = append(ps.masterPublicKey, key)
+ }
+
+ *pubs = *ps
+ return nil
+}
+
// MarshalJSON implements json.Marshaller.
func (pubs *PublicKeyShares) MarshalJSON() ([]byte, error) {
type Alias PublicKeyShares
@@ -130,6 +198,14 @@ func NewID(id []byte) ID {
return blsID
}
+// BytesID creates a new ID structure,
+// It returns err if the byte slice is not valid.
+func BytesID(id []byte) (ID, error) {
+ var blsID bls.ID
+ err := blsID.SetLittleEndian(id)
+ return blsID, err
+}
+
// NewPrivateKey creates a new PrivateKey structure.
func NewPrivateKey() *PrivateKey {
var key bls.SecretKey
@@ -327,6 +403,14 @@ func newPublicKey(prvKey *bls.SecretKey) *PublicKey {
}
}
+// newPublicKeyFromBytes create a new PublicKey structure
+// from bytes representation of bls.PublicKey
+func newPublicKeyFromBytes(b []byte) (*PublicKey, error) {
+ var pub PublicKey
+ err := pub.publicKey.Deserialize(b)
+ return &pub, err
+}
+
// PublicKey returns the public key associate this private key.
func (prv *PrivateKey) PublicKey() crypto.PublicKey {
return prv.publicKey
@@ -380,7 +464,15 @@ func (pub PublicKey) VerifySignature(
// Bytes returns []byte representation of public key.
func (pub PublicKey) Bytes() []byte {
- var bytes []byte
- pub.publicKey.Deserialize(bytes)
- return bytes
+ return pub.publicKey.Serialize()
+}
+
+// Serialize return bytes representation of public key.
+func (pub *PublicKey) Serialize() []byte {
+ return pub.publicKey.Serialize()
+}
+
+// Deserialize parses bytes representation of public key.
+func (pub *PublicKey) Deserialize(b []byte) error {
+ return pub.publicKey.Deserialize(b)
}
diff --git a/core/crypto/dkg/dkg_test.go b/core/crypto/dkg/dkg_test.go
index 84a78f4..fe7ec73 100644
--- a/core/crypto/dkg/dkg_test.go
+++ b/core/crypto/dkg/dkg_test.go
@@ -20,10 +20,12 @@ package dkg
import (
"encoding/binary"
"math/rand"
+ "reflect"
"sort"
"sync"
"testing"
+ "github.com/dexon-foundation/dexon/rlp"
"github.com/stretchr/testify/suite"
"github.com/dexon-foundation/dexon-consensus-core/common"
@@ -290,6 +292,29 @@ func (s *DKGTestSuite) TestSignature() {
s.False(pubKey.VerifySignature(hash, sig))
}
+func (s *DKGTestSuite) TestPublicKeySharesRLPEncodeDecode() {
+ p := NewEmptyPublicKeyShares()
+ for i, id := range s.genID(1) {
+ privkey := NewPrivateKey()
+ pubkey := privkey.PublicKey().(PublicKey)
+ p.shares = append(p.shares, pubkey)
+ p.shareIndex[id] = i
+ p.masterPublicKey = append(p.masterPublicKey, pubkey.publicKey)
+ }
+
+ b, err := rlp.EncodeToBytes(p)
+ s.Require().NoError(err)
+
+ var pp PublicKeyShares
+ err = rlp.DecodeBytes(b, &pp)
+ s.Require().NoError(err)
+
+ bb, err := rlp.EncodeToBytes(&pp)
+ s.Require().NoError(err)
+
+ s.Require().True(reflect.DeepEqual(b, bb))
+}
+
func TestDKG(t *testing.T) {
suite.Run(t, new(DKGTestSuite))
}
diff --git a/core/types/block.go b/core/types/block.go
index 63bcec4..c8ee3c6 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -22,10 +22,13 @@ package types
import (
"bytes"
"fmt"
+ "io"
"sort"
"sync"
"time"
+ "github.com/dexon-foundation/dexon/rlp"
+
"github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/crypto"
)
@@ -39,6 +42,25 @@ var (
}
)
+type rlpTimestamp struct {
+ time.Time
+}
+
+func (t *rlpTimestamp) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, uint64(t.UTC().UnixNano()))
+}
+
+func (t *rlpTimestamp) DecodeRLP(s *rlp.Stream) error {
+ var nano uint64
+ err := s.Decode(&nano)
+ if err == nil {
+ sec := int64(nano) / 1000000000
+ nsec := int64(nano) % 1000000000
+ t.Time = time.Unix(sec, nsec).UTC()
+ }
+ return err
+}
+
// FinalizationResult represents the result of DEXON consensus algorithm.
type FinalizationResult struct {
Randomness []byte `json:"randomness"`
@@ -46,6 +68,35 @@ type FinalizationResult struct {
Height uint64 `json:"height"`
}
+type rlpFinalizationResult struct {
+ Randomness []byte
+ Timestamp *rlpTimestamp
+ Height uint64
+}
+
+// EncodeRLP implements rlp.Encoder
+func (f *FinalizationResult) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, &rlpFinalizationResult{
+ Randomness: f.Randomness,
+ Timestamp: &rlpTimestamp{f.Timestamp},
+ Height: f.Height,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder
+func (f *FinalizationResult) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpFinalizationResult
+ err := s.Decode(&dec)
+ if err == nil {
+ *f = FinalizationResult{
+ Randomness: dec.Randomness,
+ Timestamp: dec.Timestamp.Time,
+ Height: dec.Height,
+ }
+ }
+ return err
+}
+
// Witness represents the consensus information on the compaction chain.
type Witness struct {
Timestamp time.Time `json:"timestamp"`
@@ -53,6 +104,35 @@ type Witness struct {
Data []byte `json:"data"`
}
+type rlpWitness struct {
+ Timestamp *rlpTimestamp
+ Height uint64
+ Data []byte
+}
+
+// EncodeRLP implements rlp.Encoder
+func (w *Witness) EncodeRLP(writer io.Writer) error {
+ return rlp.Encode(writer, rlpWitness{
+ Timestamp: &rlpTimestamp{w.Timestamp},
+ Height: w.Height,
+ Data: w.Data,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder
+func (w *Witness) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpWitness
+ err := s.Decode(&dec)
+ if err == nil {
+ *w = Witness{
+ Timestamp: dec.Timestamp.Time,
+ Height: dec.Height,
+ Data: dec.Data,
+ }
+ }
+ return err
+}
+
// RecycleBlock put unused block into cache, which might be reused if
// not garbage collected.
func RecycleBlock(b *Block) {
@@ -82,6 +162,60 @@ type Block struct {
CRSSignature crypto.Signature `json:"crs_signature"`
}
+type rlpBlock struct {
+ ProposerID NodeID
+ ParentHash common.Hash
+ Hash common.Hash
+ Position Position
+ Timestamp *rlpTimestamp
+ Acks common.SortedHashes
+ Payload []byte
+ Witness *Witness
+ Finalization *FinalizationResult
+ Signature crypto.Signature
+
+ CRSSignature crypto.Signature
+}
+
+// EncodeRLP implements rlp.Encoder
+func (b *Block) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, rlpBlock{
+ ProposerID: b.ProposerID,
+ ParentHash: b.ParentHash,
+ Hash: b.Hash,
+ Position: b.Position,
+ Timestamp: &rlpTimestamp{b.Timestamp},
+ Acks: b.Acks,
+ Payload: b.Payload,
+ Witness: &b.Witness,
+ Finalization: &b.Finalization,
+ Signature: b.Signature,
+ CRSSignature: b.CRSSignature,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder
+func (b *Block) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpBlock
+ err := s.Decode(&dec)
+ if err == nil {
+ *b = Block{
+ ProposerID: dec.ProposerID,
+ ParentHash: dec.ParentHash,
+ Hash: dec.Hash,
+ Position: dec.Position,
+ Timestamp: dec.Timestamp.Time,
+ Acks: dec.Acks,
+ Payload: dec.Payload,
+ Witness: *dec.Witness,
+ Finalization: *dec.Finalization,
+ Signature: dec.Signature,
+ CRSSignature: dec.CRSSignature,
+ }
+ }
+ return err
+}
+
func (b *Block) String() string {
return fmt.Sprintf("Block(%v:%d:%d)", b.Hash.String()[:6],
b.Position.ChainID, b.Position.Height)
diff --git a/core/types/block_test.go b/core/types/block_test.go
index 49eaa86..758619d 100644
--- a/core/types/block_test.go
+++ b/core/types/block_test.go
@@ -24,9 +24,11 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/suite"
+
"github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/crypto"
- "github.com/stretchr/testify/suite"
+ "github.com/dexon-foundation/dexon/rlp"
)
type BlockTestSuite struct {
@@ -51,14 +53,14 @@ func (s *BlockTestSuite) createRandomBlock() *Block {
common.NewRandomHash(),
common.NewRandomHash(),
}),
- Timestamp: time.Now().Add(time.Duration(rand.Int())),
+ Timestamp: time.Now().UTC(),
Witness: Witness{
Height: rand.Uint64(),
- Timestamp: time.Now().Add(time.Duration(rand.Int())),
+ Timestamp: time.Now().UTC(),
Data: s.randomBytes(),
},
Finalization: FinalizationResult{
- Timestamp: time.Now().Add(time.Duration(rand.Int())),
+ Timestamp: time.Now().UTC(),
Height: rand.Uint64(),
Randomness: s.randomBytes(),
},
@@ -66,6 +68,7 @@ func (s *BlockTestSuite) createRandomBlock() *Block {
Signature: crypto.Signature{Signature: s.randomBytes()},
CRSSignature: crypto.Signature{Signature: s.randomBytes()},
}
+
return b
}
@@ -178,6 +181,18 @@ func (s *BlockTestSuite) TestClone() {
}
}
+func (s *BlockTestSuite) TestRLPEncodeDecode() {
+ block := s.createRandomBlock()
+ b, err := rlp.EncodeToBytes(block)
+ s.Require().NoError(err)
+
+ var dec Block
+ err = rlp.DecodeBytes(b, &dec)
+ s.Require().NoError(err)
+
+ s.Require().True(reflect.DeepEqual(block, &dec))
+}
+
func TestBlock(t *testing.T) {
suite.Run(t, new(BlockTestSuite))
}
diff --git a/core/types/dkg.go b/core/types/dkg.go
index 6018ebd..c0a42ee 100644
--- a/core/types/dkg.go
+++ b/core/types/dkg.go
@@ -20,6 +20,9 @@ package types
import (
"encoding/json"
"fmt"
+ "io"
+
+ "github.com/dexon-foundation/dexon/rlp"
"github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/crypto"
@@ -59,6 +62,47 @@ func (d *DKGMasterPublicKey) String() string {
d.Round)
}
+type rlpDKGMasterPublicKey struct {
+ ProposerID NodeID
+ Round uint64
+ DKGID []byte
+ PublicKeyShares *dkg.PublicKeyShares
+ Signature crypto.Signature
+}
+
+// EncodeRLP implements rlp.Encoder
+func (d *DKGMasterPublicKey) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, rlpDKGMasterPublicKey{
+ ProposerID: d.ProposerID,
+ Round: d.Round,
+ DKGID: d.DKGID.GetLittleEndian(),
+ PublicKeyShares: &d.PublicKeyShares,
+ Signature: d.Signature,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder
+func (d *DKGMasterPublicKey) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpDKGMasterPublicKey
+ if err := s.Decode(&dec); err != nil {
+ return err
+ }
+
+ id, err := dkg.BytesID(dec.DKGID)
+ if err != nil {
+ return err
+ }
+
+ *d = DKGMasterPublicKey{
+ ProposerID: dec.ProposerID,
+ Round: dec.Round,
+ DKGID: id,
+ PublicKeyShares: *dec.PublicKeyShares,
+ Signature: dec.Signature,
+ }
+ return err
+}
+
// NewDKGMasterPublicKey returns a new DKGMasterPublicKey instance.
func NewDKGMasterPublicKey() *DKGMasterPublicKey {
return &DKGMasterPublicKey{
diff --git a/core/types/dkg_test.go b/core/types/dkg_test.go
new file mode 100644
index 0000000..010d460
--- /dev/null
+++ b/core/types/dkg_test.go
@@ -0,0 +1,62 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package types
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/suite"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/crypto"
+ "github.com/dexon-foundation/dexon/rlp"
+)
+
+type DKGTestSuite struct {
+ suite.Suite
+}
+
+func (s *DKGTestSuite) TestRLPEncodeDecode() {
+ d := DKGMasterPublicKey{
+ ProposerID: NodeID{common.Hash{1, 2, 3}},
+ Round: 10,
+ Signature: crypto.Signature{
+ Type: "123",
+ Signature: []byte{4, 5, 6},
+ },
+ }
+
+ b, err := rlp.EncodeToBytes(&d)
+ s.Require().NoError(err)
+
+ var dd DKGMasterPublicKey
+ err = rlp.DecodeBytes(b, &dd)
+ s.Require().NoError(err)
+
+ bb, err := rlp.EncodeToBytes(&dd)
+ s.Require().NoError(err)
+ s.Require().True(reflect.DeepEqual(b, bb))
+ s.Require().True(d.ProposerID.Equal(dd.ProposerID))
+ s.Require().True(d.Round == dd.Round)
+ s.Require().True(reflect.DeepEqual(d.Signature, dd.Signature))
+}
+
+func TestDKG(t *testing.T) {
+ suite.Run(t, new(DKGTestSuite))
+}