Skip to content

Commit

Permalink
*: use generic hashes implementation for DBFT
Browse files Browse the repository at this point in the history
A part of #2. Use generics instead of util.Uint160 and util.Uint256
types for DBFT and related components. Keep util.Uint160 and util.Uint256
only for specific DBFT implementation in testing code.

The following regressions/behaviour changes were made to properly
apply generics:
1. `dbft.Option` alias is removed since type parameters can't be defined
   on aliases (generic type aliases are prohibited). Ref.
   golang/go#46477.
2. Default dBFT configuration is reduced: all payload-specific defaults
   are removed, as described in #91.
   It is done because default dBFT configuration should not depend on any
   implementation-specific hash type.
3. DBFT configuration validation check is extended wrt point 2.
4. The check if generic `dbft.DBFT` type implements generic `dbft.Service`
   interface is removed since such check should be performed on particular
   (non-generic) DBFT implementation.

Signed-off-by: Anna Shaleva <[email protected]>
  • Loading branch information
AnnaShaleva committed Feb 13, 2024
1 parent 92d9aec commit ef1e5c6
Show file tree
Hide file tree
Showing 21 changed files with 526 additions and 393 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@ written in [TLA⁺](https://lamport.azurewebsites.net/tla/tla.html) language.

## Design and structure
1. All control flow is done in main package. Most of the code which communicates with external
world (event time events) is hidden behind interfaces and callbacks. As a consequence it is
highly flexible and extendable. Description of config options can be found in `config.go`.
world (event time events) is hidden behind interfaces, callbacks and generic parameters. As a
consequence it is highly flexible and extendable. Description of config options can be found
in `config.go`.
2. `crypto` package contains `PrivateKey`/`PublicKey` interfaces which permits usage of one's own
cryptography for signing blocks on `Commit` stage.
Default implementation with ECDSA signatures is provided, BLS multisignatures could be added
in the nearest future.
3. `crypto` package contains `Hash`/`Address` interfaces which permits usage of one's own
hash/address implementation without additional overhead on conversions. Instantiate dBFT with
custom hash/address implementation that matches requirements specified in the corresponding
documentation.
3. `block` package contains `Block` and `Transaction` abstractions.
Every block must be able to be signed and verified as well as
implement setters and getters for main fields. Minimal default implementation is provided.
Expand Down
22 changes: 11 additions & 11 deletions block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ type (
}

// Block is a generic interface for a block used by dbft.
Block interface {
Block[H crypto.Hash, A crypto.Address] interface {
// Hash returns block hash.
Hash() util.Uint256
Hash() H

Version() uint32
// PrevHash returns previous block hash.
PrevHash() util.Uint256
PrevHash() H
// MerkleRoot returns a merkle root of the transaction hashes.
MerkleRoot() util.Uint256
MerkleRoot() H
// Timestamp returns block's proposal timestamp.
Timestamp() uint64
// Index returns block index.
Index() uint32
// ConsensusData is a random nonce.
ConsensusData() uint64
// NextConsensus returns hash of the validators of the next block.
NextConsensus() util.Uint160
NextConsensus() A

// Signature returns block's signature.
Signature() []byte
Expand All @@ -49,16 +49,16 @@ type (
Verify(key crypto.PublicKey, sign []byte) error

// Transactions returns block's transaction list.
Transactions() []Transaction
Transactions() []Transaction[H]
// SetTransactions sets block's transaction list.
SetTransactions([]Transaction)
SetTransactions([]Transaction[H])
}

neoBlock struct {
base

consensusData uint64
transactions []Transaction
transactions []Transaction[util.Uint256]
signature []byte
hash *util.Uint256
}
Expand Down Expand Up @@ -100,17 +100,17 @@ func (b *neoBlock) ConsensusData() uint64 {
}

// Transactions implements Block interface.
func (b *neoBlock) Transactions() []Transaction {
func (b *neoBlock) Transactions() []Transaction[util.Uint256] {
return b.transactions
}

// SetTransactions implements Block interface.
func (b *neoBlock) SetTransactions(txx []Transaction) {
func (b *neoBlock) SetTransactions(txx []Transaction[util.Uint256]) {
b.transactions = txx
}

// NewBlock returns new block.
func NewBlock(timestamp uint64, index uint32, nextConsensus util.Uint160, prevHash util.Uint256, version uint32, nonce uint64, txHashes []util.Uint256) Block {
func NewBlock(timestamp uint64, index uint32, nextConsensus util.Uint160, prevHash util.Uint256, version uint32, nonce uint64, txHashes []util.Uint256) Block[util.Uint256, util.Uint160] {
block := new(neoBlock)
block.base.Timestamp = uint32(timestamp / 1000000000)
block.base.Index = index
Expand Down
2 changes: 1 addition & 1 deletion block/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestNeoBlock_Setters(t *testing.T) {

require.Equal(t, util.Uint256{}, b.Hash())

txs := []Transaction{testTx(1), testTx(2)}
txs := []Transaction[util.Uint256]{testTx(1), testTx(2)}
b.SetTransactions(txs)
assert.Equal(t, txs, b.Transactions())

Expand Down
6 changes: 3 additions & 3 deletions block/transaction.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package block

import (
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/dbft/crypto"
)

// Transaction is a generic transaction interface.
type Transaction interface {
type Transaction[H crypto.Hash] interface {
// Hash must return cryptographic hash of the transaction.
// Transactions which have equal hashes are considered equal.
Hash() util.Uint256
Hash() H
}
6 changes: 3 additions & 3 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"go.uber.org/zap"
)

func (d *DBFT) checkPrepare() {
func (d *DBFT[H, A]) checkPrepare() {
if !d.hasAllTransactions() {
d.Logger.Debug("check prepare: some transactions are missing", zap.Any("hashes", d.MissingTransactions))
return
Expand Down Expand Up @@ -37,7 +37,7 @@ func (d *DBFT) checkPrepare() {
}
}

func (d *DBFT) checkCommit() {
func (d *DBFT[H, A]) checkCommit() {
if !d.hasAllTransactions() {
d.Logger.Debug("check commit: some transactions are missing", zap.Any("hashes", d.MissingTransactions))
return
Expand Down Expand Up @@ -78,7 +78,7 @@ func (d *DBFT) checkCommit() {
// new height.
}

func (d *DBFT) checkChangeView(view byte) {
func (d *DBFT[H, A]) checkChangeView(view byte) {
if d.ViewNumber >= view {
return
}
Expand Down
Loading

0 comments on commit ef1e5c6

Please sign in to comment.