Skip to content

Commit 968e504

Browse files
authored
Consolidate istanbul.Message encoding/decoding (#1592)
Message decoding and encoding, prevously happend in 2 steps. This commit makes decoding and encoding a message an atomic operation, either it succeeds or it fails. This allows us to decode in just one place in the code, allowing us to have a consistent approach to decode errors. By being able to respond to decode errors at a higer level in the stack, we remove the need to pass errors back up the stack to indicate invalid messages. It also helps separate encoding and decoding logic from our domain logic.
1 parent 76f5918 commit 968e504

26 files changed

+841
-1170
lines changed

consensus/istanbul/backend/announce.go

Lines changed: 49 additions & 174 deletions
Large diffs are not rendered by default.

consensus/istanbul/backend/announce_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@ func TestAnnounceGossipQueryMsg(t *testing.T) {
3636

3737
engine0Enode := engine0.SelfNode()
3838

39-
w1 := engine1.wallets()
4039
// Create version certificate messages for engine1 and engine2, so that engine0 will send a queryEnodeMessage to them
41-
vCert1, err := generateVersionCertificate(w1.Ecdsa.Address, w1.Ecdsa.PublicKey, engine1AnnounceVersion, w1.Ecdsa.Sign)
40+
vCert1, err := istanbul.NewVersionCertificate(engine1AnnounceVersion, engine1.Sign)
4241
if err != nil {
4342
t.Errorf("Error in generating version certificate for engine1. Error: %v", err)
4443
}
45-
w2 := engine2.wallets()
46-
vCert2, err := generateVersionCertificate(w2.Ecdsa.Address, w2.Ecdsa.PublicKey, engine2AnnounceVersion, w2.Ecdsa.Sign)
44+
45+
vCert2, err := istanbul.NewVersionCertificate(engine1AnnounceVersion, engine2.Sign)
4746
if err != nil {
4847
t.Errorf("Error in generating version certificate for engine2. Error: %v", err)
4948
}
5049

5150
// Have engine0 handle vCert messages from engine1 and engine2
52-
vCert1MsgPayload, err := encodeVersionCertificatesMsg([]*versionCertificate{vCert1})
51+
52+
vCert1MsgPayload, err := istanbul.NewVersionCeritifcatesMessage([]*istanbul.VersionCertificate{vCert1}, engine1Address).Payload()
5353
if err != nil {
5454
t.Errorf("Error in encoding vCert1. Error: %v", err)
5555
}
@@ -58,7 +58,7 @@ func TestAnnounceGossipQueryMsg(t *testing.T) {
5858
t.Errorf("Error in handling vCert1. Error: %v", err)
5959
}
6060

61-
vCert2MsgPayload, err := encodeVersionCertificatesMsg([]*versionCertificate{vCert2})
61+
vCert2MsgPayload, err := istanbul.NewVersionCeritifcatesMessage([]*istanbul.VersionCertificate{vCert2}, engine2Address).Payload()
6262
if err != nil {
6363
t.Errorf("Error in encoding vCert2. Error: %v", err)
6464
}

consensus/istanbul/backend/internal/enodes/version_certificate_db.go

Lines changed: 20 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@
1717
package enodes
1818

1919
import (
20-
"crypto/ecdsa"
21-
"encoding/hex"
2220
"fmt"
23-
"io"
2421
"strings"
2522

2623
"github.com/syndtr/goleveldb/leveldb"
2724
"github.com/syndtr/goleveldb/leveldb/opt"
2825

2926
"github.com/celo-org/celo-blockchain/common"
27+
"github.com/celo-org/celo-blockchain/consensus/istanbul"
3028
"github.com/celo-org/celo-blockchain/consensus/istanbul/backend/internal/db"
31-
"github.com/celo-org/celo-blockchain/crypto"
3229
"github.com/celo-org/celo-blockchain/log"
3330
"github.com/celo-org/celo-blockchain/rlp"
3431
)
@@ -43,55 +40,14 @@ type VersionCertificateDB struct {
4340
logger log.Logger
4441
}
4542

46-
// VersionCertificateEntry is an entry in the VersionCertificateDB.
47-
// It's a signed message from a registered or active validator indicating
48-
// the most recent version of its enode.
49-
type VersionCertificateEntry struct {
50-
Address common.Address
51-
PublicKey *ecdsa.PublicKey
52-
Version uint
53-
Signature []byte
54-
}
55-
56-
func versionCertificateEntryFromGenericEntry(entry db.GenericEntry) (*VersionCertificateEntry, error) {
57-
signedAnnVersionEntry, ok := entry.(*VersionCertificateEntry)
43+
func versionCertificateEntryFromGenericEntry(entry db.GenericEntry) (*istanbul.VersionCertificate, error) {
44+
signedAnnVersionEntry, ok := entry.(*istanbul.VersionCertificate)
5845
if !ok {
5946
return nil, errIncorrectEntryType
6047
}
6148
return signedAnnVersionEntry, nil
6249
}
6350

64-
// EncodeRLP serializes VersionCertificateEntry into the Ethereum RLP format.
65-
func (entry *VersionCertificateEntry) EncodeRLP(w io.Writer) error {
66-
encodedPublicKey := crypto.FromECDSAPub(entry.PublicKey)
67-
return rlp.Encode(w, []interface{}{entry.Address, encodedPublicKey, entry.Version, entry.Signature})
68-
}
69-
70-
// DecodeRLP implements rlp.Decoder, and load the VersionCertificateEntry fields from a RLP stream.
71-
func (entry *VersionCertificateEntry) DecodeRLP(s *rlp.Stream) error {
72-
var content struct {
73-
Address common.Address
74-
PublicKey []byte
75-
Version uint
76-
Signature []byte
77-
}
78-
79-
if err := s.Decode(&content); err != nil {
80-
return err
81-
}
82-
decodedPublicKey, err := crypto.UnmarshalPubkey(content.PublicKey)
83-
if err != nil {
84-
return err
85-
}
86-
entry.Address, entry.PublicKey, entry.Version, entry.Signature = content.Address, decodedPublicKey, content.Version, content.Signature
87-
return nil
88-
}
89-
90-
// String gives a string representation of VersionCertificateEntry
91-
func (entry *VersionCertificateEntry) String() string {
92-
return fmt.Sprintf("{Address: %v, Version: %v, Signature: %v}", entry.Address, entry.Version, hex.EncodeToString(entry.Signature))
93-
}
94-
9551
// OpenVersionCertificateDB opens a signed announce version database for storing
9652
// VersionCertificates. If no path is given an in-memory, temporary database is constructed.
9753
func OpenVersionCertificateDB(path string) (*VersionCertificateDB, error) {
@@ -119,7 +75,7 @@ func (svdb *VersionCertificateDB) String() string {
11975
var b strings.Builder
12076
b.WriteString("VersionCertificateDB:")
12177

122-
err := svdb.iterate(func(address common.Address, entry *VersionCertificateEntry) error {
78+
err := svdb.iterate(func(address common.Address, entry *istanbul.VersionCertificate) error {
12379
fmt.Fprintf(&b, " [%s => %s]", address.String(), entry.String())
12480
return nil
12581
})
@@ -133,17 +89,17 @@ func (svdb *VersionCertificateDB) String() string {
13389

13490
// Upsert inserts any new entries or entries with a Version higher than the
13591
// existing version. Returns any new or updated entries
136-
func (svdb *VersionCertificateDB) Upsert(savEntries []*VersionCertificateEntry) ([]*VersionCertificateEntry, error) {
92+
func (svdb *VersionCertificateDB) Upsert(savEntries []*istanbul.VersionCertificate) ([]*istanbul.VersionCertificate, error) {
13793
logger := svdb.logger.New("func", "Upsert")
13894

139-
var newEntries []*VersionCertificateEntry
95+
var newEntries []*istanbul.VersionCertificate
14096

14197
getExistingEntry := func(entry db.GenericEntry) (db.GenericEntry, error) {
14298
savEntry, err := versionCertificateEntryFromGenericEntry(entry)
14399
if err != nil {
144100
return entry, err
145101
}
146-
return svdb.Get(savEntry.Address)
102+
return svdb.Get(savEntry.Address())
147103
}
148104

149105
onNewEntry := func(batch *leveldb.Batch, entry db.GenericEntry) error {
@@ -155,7 +111,7 @@ func (svdb *VersionCertificateDB) Upsert(savEntries []*VersionCertificateEntry)
155111
if err != nil {
156112
return err
157113
}
158-
batch.Put(addressKey(savEntry.Address), savEntryBytes)
114+
batch.Put(addressKey(savEntry.Address()), savEntryBytes)
159115
newEntries = append(newEntries, savEntry)
160116
logger.Trace("Updating with new entry",
161117
"address", savEntry.Address, "new version", savEntry.Version)
@@ -190,10 +146,10 @@ func (svdb *VersionCertificateDB) Upsert(savEntries []*VersionCertificateEntry)
190146
return newEntries, nil
191147
}
192148

193-
// Get gets the VersionCertificateEntry entry with address `address`.
149+
// Get gets the istanbul.VersionCertificateEntry entry with address `address`.
194150
// Returns an error if no entry exists.
195-
func (svdb *VersionCertificateDB) Get(address common.Address) (*VersionCertificateEntry, error) {
196-
var entry VersionCertificateEntry
151+
func (svdb *VersionCertificateDB) Get(address common.Address) (*istanbul.VersionCertificate, error) {
152+
var entry istanbul.VersionCertificate
197153
entryBytes, err := svdb.gdb.Get(addressKey(address))
198154
if err != nil {
199155
return nil, err
@@ -214,10 +170,10 @@ func (svdb *VersionCertificateDB) GetVersion(address common.Address) (uint, erro
214170
return signedAnnVersion.Version, nil
215171
}
216172

217-
// GetAll gets each VersionCertificateEntry in the db
218-
func (svdb *VersionCertificateDB) GetAll() ([]*VersionCertificateEntry, error) {
219-
var entries []*VersionCertificateEntry
220-
err := svdb.iterate(func(address common.Address, entry *VersionCertificateEntry) error {
173+
// GetAll gets each istanbul.VersionCertificateEntry in the db
174+
func (svdb *VersionCertificateDB) GetAll() ([]*istanbul.VersionCertificate, error) {
175+
var entries []*istanbul.VersionCertificate
176+
err := svdb.iterate(func(address common.Address, entry *istanbul.VersionCertificate) error {
221177
entries = append(entries, entry)
222178
return nil
223179
})
@@ -237,7 +193,7 @@ func (svdb *VersionCertificateDB) Remove(address common.Address) error {
237193
// Prune will remove entries for all addresses not present in addressesToKeep
238194
func (svdb *VersionCertificateDB) Prune(addressesToKeep map[common.Address]bool) error {
239195
batch := new(leveldb.Batch)
240-
err := svdb.iterate(func(address common.Address, entry *VersionCertificateEntry) error {
196+
err := svdb.iterate(func(address common.Address, entry *istanbul.VersionCertificate) error {
241197
if !addressesToKeep[address] {
242198
svdb.logger.Trace("Deleting entry", "address", address)
243199
batch.Delete(addressKey(address))
@@ -251,13 +207,13 @@ func (svdb *VersionCertificateDB) Prune(addressesToKeep map[common.Address]bool)
251207
}
252208

253209
// iterate will call `onEntry` for each entry in the db
254-
func (svdb *VersionCertificateDB) iterate(onEntry func(common.Address, *VersionCertificateEntry) error) error {
210+
func (svdb *VersionCertificateDB) iterate(onEntry func(common.Address, *istanbul.VersionCertificate) error) error {
255211
logger := svdb.logger.New("func", "iterate")
256212
// Only target address keys
257213
keyPrefix := []byte(dbAddressPrefix)
258214

259215
onDBEntry := func(key []byte, value []byte) error {
260-
var entry VersionCertificateEntry
216+
var entry istanbul.VersionCertificate
261217
if err := rlp.DecodeBytes(value, &entry); err != nil {
262218
return err
263219
}
@@ -285,9 +241,9 @@ type VersionCertificateEntryInfo struct {
285241
// Intended for RPC use
286242
func (svdb *VersionCertificateDB) Info() (map[string]*VersionCertificateEntryInfo, error) {
287243
dbInfo := make(map[string]*VersionCertificateEntryInfo)
288-
err := svdb.iterate(func(address common.Address, entry *VersionCertificateEntry) error {
244+
err := svdb.iterate(func(address common.Address, entry *istanbul.VersionCertificate) error {
289245
dbInfo[address.Hex()] = &VersionCertificateEntryInfo{
290-
Address: entry.Address.Hex(),
246+
Address: entry.Address().Hex(),
291247
Version: entry.Version,
292248
}
293249
return nil

0 commit comments

Comments
 (0)