diff --git a/block.go b/block.go index c849fc89..af3bf6b2 100644 --- a/block.go +++ b/block.go @@ -1,7 +1,7 @@ package dbft // Block is a generic interface for a block used by dbft. -type Block[H Hash, A Address] interface { +type Block[H Hash] interface { // Hash returns block hash. Hash() H @@ -16,8 +16,6 @@ type Block[H Hash, A Address] interface { Index() uint32 // ConsensusData is a random nonce. ConsensusData() uint64 - // NextConsensus returns hash of the validators of the next block. - NextConsensus() A // Signature returns block's signature. Signature() []byte diff --git a/check.go b/check.go index a3a3d72d..4b4b9e15 100644 --- a/check.go +++ b/check.go @@ -4,7 +4,7 @@ import ( "go.uber.org/zap" ) -func (d *DBFT[H, A]) checkPrepare() { +func (d *DBFT[H]) checkPrepare() { if !d.hasAllTransactions() { d.Logger.Debug("check prepare: some transactions are missing", zap.Any("hashes", d.MissingTransactions)) return @@ -36,7 +36,7 @@ func (d *DBFT[H, A]) checkPrepare() { } } -func (d *DBFT[H, A]) checkCommit() { +func (d *DBFT[H]) checkCommit() { if !d.hasAllTransactions() { d.Logger.Debug("check commit: some transactions are missing", zap.Any("hashes", d.MissingTransactions)) return @@ -77,7 +77,7 @@ func (d *DBFT[H, A]) checkCommit() { // new height. } -func (d *DBFT[H, A]) checkChangeView(view byte) { +func (d *DBFT[H]) checkChangeView(view byte) { if d.ViewNumber >= view { return } diff --git a/config.go b/config.go index d0b3f316..014785e4 100644 --- a/config.go +++ b/config.go @@ -10,7 +10,7 @@ import ( ) // Config contains initialization and working parameters for dBFT. -type Config[H Hash, A Address] struct { +type Config[H Hash] struct { // Logger Logger *zap.Logger // Timer @@ -26,7 +26,7 @@ type Config[H Hash, A Address] struct { // together with it's key pair. GetKeyPair func([]PublicKey) (int, PrivateKey, PublicKey) // NewBlockFromContext should allocate, fill from Context and return new block.Block. - NewBlockFromContext func(ctx *Context[H, A]) Block[H, A] + NewBlockFromContext func(ctx *Context[H]) Block[H] // RequestTx is a callback which is called when transaction contained // in current block can't be found in memory pool. RequestTx func(h ...H) @@ -39,13 +39,13 @@ type Config[H Hash, A Address] struct { // to be proposed in a new block. GetVerified func() []Transaction[H] // VerifyBlock verifies if block is valid. - VerifyBlock func(b Block[H, A]) bool + VerifyBlock func(b Block[H]) bool // Broadcast should broadcast payload m to the consensus nodes. - Broadcast func(m ConsensusPayload[H, A]) + Broadcast func(m ConsensusPayload[H]) // ProcessBlock is called every time new block is accepted. - ProcessBlock func(b Block[H, A]) + ProcessBlock func(b Block[H]) // GetBlock should return block with hash. - GetBlock func(h H) Block[H, A] + GetBlock func(h H) Block[H] // WatchOnly tells if a node should only watch. WatchOnly func() bool // CurrentHeight returns index of the last accepted block. @@ -57,12 +57,10 @@ type Config[H Hash, A Address] struct { // list of the validators of the next block. // If this function ever returns 0-length slice, dbft will panic. GetValidators func(...Transaction[H]) []PublicKey - // GetConsensusAddress returns hash of the validator list. - GetConsensusAddress func(...PublicKey) A // NewConsensusPayload is a constructor for payload.ConsensusPayload. - NewConsensusPayload func(*Context[H, A], MessageType, any) ConsensusPayload[H, A] + NewConsensusPayload func(*Context[H], MessageType, any) ConsensusPayload[H] // NewPrepareRequest is a constructor for payload.PrepareRequest. - NewPrepareRequest func(ts uint64, nonce uint64, nextConsensus A, transactionHashes []H) PrepareRequest[H, A] + NewPrepareRequest func(ts uint64, nonce uint64, transactionHashes []H) PrepareRequest[H] // NewPrepareResponse is a constructor for payload.PrepareResponse. NewPrepareResponse func(preparationHash H) PrepareResponse[H] // NewChangeView is a constructor for payload.ChangeView. @@ -72,20 +70,20 @@ type Config[H Hash, A Address] struct { // NewRecoveryRequest is a constructor for payload.RecoveryRequest. NewRecoveryRequest func(ts uint64) RecoveryRequest // NewRecoveryMessage is a constructor for payload.RecoveryMessage. - NewRecoveryMessage func() RecoveryMessage[H, A] + NewRecoveryMessage func() RecoveryMessage[H] // VerifyPrepareRequest can perform external payload verification and returns true iff it was successful. - VerifyPrepareRequest func(p ConsensusPayload[H, A]) error + VerifyPrepareRequest func(p ConsensusPayload[H]) error // VerifyPrepareResponse performs external PrepareResponse verification and returns nil if it's successful. - VerifyPrepareResponse func(p ConsensusPayload[H, A]) error + VerifyPrepareResponse func(p ConsensusPayload[H]) error } const defaultSecondsPerBlock = time.Second * 15 const defaultTimestampIncrement = uint64(time.Millisecond / time.Nanosecond) -func defaultConfig[H Hash, A Address]() *Config[H, A] { +func defaultConfig[H Hash]() *Config[H] { // fields which are set to nil must be provided from client - return &Config[H, A]{ + return &Config[H]{ Logger: zap.NewNop(), Timer: timer.New(), SecondsPerBlock: defaultSecondsPerBlock, @@ -95,21 +93,21 @@ func defaultConfig[H Hash, A Address]() *Config[H, A] { StopTxFlow: func() {}, GetTx: func(H) Transaction[H] { return nil }, GetVerified: func() []Transaction[H] { return make([]Transaction[H], 0) }, - VerifyBlock: func(Block[H, A]) bool { return true }, - Broadcast: func(ConsensusPayload[H, A]) {}, - ProcessBlock: func(Block[H, A]) {}, - GetBlock: func(H) Block[H, A] { return nil }, + VerifyBlock: func(Block[H]) bool { return true }, + Broadcast: func(ConsensusPayload[H]) {}, + ProcessBlock: func(Block[H]) {}, + GetBlock: func(H) Block[H] { return nil }, WatchOnly: func() bool { return false }, CurrentHeight: nil, CurrentBlockHash: nil, GetValidators: nil, - VerifyPrepareRequest: func(ConsensusPayload[H, A]) error { return nil }, - VerifyPrepareResponse: func(ConsensusPayload[H, A]) error { return nil }, + VerifyPrepareRequest: func(ConsensusPayload[H]) error { return nil }, + VerifyPrepareResponse: func(ConsensusPayload[H]) error { return nil }, } } -func checkConfig[H Hash, A Address](cfg *Config[H, A]) error { +func checkConfig[H Hash](cfg *Config[H]) error { if cfg.GetKeyPair == nil { return errors.New("private key is nil") } else if cfg.CurrentHeight == nil { @@ -120,8 +118,6 @@ func checkConfig[H Hash, A Address](cfg *Config[H, A]) error { return errors.New("GetValidators is nil") } else if cfg.NewBlockFromContext == nil { return errors.New("NewBlockFromContext is nil") - } else if cfg.GetConsensusAddress == nil { - return errors.New("GetConsensusAddress is nil") } else if cfg.NewConsensusPayload == nil { return errors.New("NewConsensusPayload is nil") } else if cfg.NewPrepareRequest == nil { @@ -143,13 +139,13 @@ func checkConfig[H Hash, A Address](cfg *Config[H, A]) error { // WithKeyPair sets GetKeyPair to a function returning default key pair // if it is present in a list of validators. -func WithKeyPair[H Hash, A Address](priv PrivateKey, pub PublicKey) func(config *Config[H, A]) { +func WithKeyPair[H Hash](priv PrivateKey, pub PublicKey) func(config *Config[H]) { myPub, err := pub.MarshalBinary() if err != nil { return nil } - return func(cfg *Config[H, A]) { + return func(cfg *Config[H]) { cfg.GetKeyPair = func(ps []PublicKey) (int, PrivateKey, PublicKey) { for i := range ps { pi, err := ps[i].MarshalBinary() @@ -166,197 +162,190 @@ func WithKeyPair[H Hash, A Address](priv PrivateKey, pub PublicKey) func(config } // WithGetKeyPair sets GetKeyPair. -func WithGetKeyPair[H Hash, A Address](f func([]PublicKey) (int, PrivateKey, PublicKey)) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithGetKeyPair[H Hash](f func([]PublicKey) (int, PrivateKey, PublicKey)) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.GetKeyPair = f } } // WithLogger sets Logger. -func WithLogger[H Hash, A Address](log *zap.Logger) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithLogger[H Hash](log *zap.Logger) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.Logger = log } } // WithTimer sets Timer. -func WithTimer[H Hash, A Address](t timer.Timer) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithTimer[H Hash](t timer.Timer) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.Timer = t } } // WithSecondsPerBlock sets SecondsPerBlock. -func WithSecondsPerBlock[H Hash, A Address](d time.Duration) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithSecondsPerBlock[H Hash](d time.Duration) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.SecondsPerBlock = d } } // WithTimestampIncrement sets TimestampIncrement. -func WithTimestampIncrement[H Hash, A Address](u uint64) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithTimestampIncrement[H Hash](u uint64) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.TimestampIncrement = u } } // WithNewBlockFromContext sets NewBlockFromContext. -func WithNewBlockFromContext[H Hash, A Address](f func(ctx *Context[H, A]) Block[H, A]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewBlockFromContext[H Hash](f func(ctx *Context[H]) Block[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewBlockFromContext = f } } // WithRequestTx sets RequestTx. -func WithRequestTx[H Hash, A Address](f func(h ...H)) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithRequestTx[H Hash](f func(h ...H)) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.RequestTx = f } } // WithStopTxFlow sets StopTxFlow. -func WithStopTxFlow[H Hash, A Address](f func()) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithStopTxFlow[H Hash](f func()) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.StopTxFlow = f } } // WithGetTx sets GetTx. -func WithGetTx[H Hash, A Address](f func(h H) Transaction[H]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithGetTx[H Hash](f func(h H) Transaction[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.GetTx = f } } // WithGetVerified sets GetVerified. -func WithGetVerified[H Hash, A Address](f func() []Transaction[H]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithGetVerified[H Hash](f func() []Transaction[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.GetVerified = f } } // WithVerifyBlock sets VerifyBlock. -func WithVerifyBlock[H Hash, A Address](f func(b Block[H, A]) bool) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithVerifyBlock[H Hash](f func(b Block[H]) bool) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.VerifyBlock = f } } // WithBroadcast sets Broadcast. -func WithBroadcast[H Hash, A Address](f func(m ConsensusPayload[H, A])) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithBroadcast[H Hash](f func(m ConsensusPayload[H])) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.Broadcast = f } } // WithProcessBlock sets ProcessBlock. -func WithProcessBlock[H Hash, A Address](f func(b Block[H, A])) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithProcessBlock[H Hash](f func(b Block[H])) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.ProcessBlock = f } } // WithGetBlock sets GetBlock. -func WithGetBlock[H Hash, A Address](f func(h H) Block[H, A]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithGetBlock[H Hash](f func(h H) Block[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.GetBlock = f } } // WithWatchOnly sets WatchOnly. -func WithWatchOnly[H Hash, A Address](f func() bool) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithWatchOnly[H Hash](f func() bool) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.WatchOnly = f } } // WithCurrentHeight sets CurrentHeight. -func WithCurrentHeight[H Hash, A Address](f func() uint32) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithCurrentHeight[H Hash](f func() uint32) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.CurrentHeight = f } } // WithCurrentBlockHash sets CurrentBlockHash. -func WithCurrentBlockHash[H Hash, A Address](f func() H) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithCurrentBlockHash[H Hash](f func() H) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.CurrentBlockHash = f } } // WithGetValidators sets GetValidators. -func WithGetValidators[H Hash, A Address](f func(...Transaction[H]) []PublicKey) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithGetValidators[H Hash](f func(...Transaction[H]) []PublicKey) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.GetValidators = f } } -// WithGetConsensusAddress sets GetConsensusAddress. -func WithGetConsensusAddress[H Hash, A Address](f func(keys ...PublicKey) A) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { - cfg.GetConsensusAddress = f - } -} - // WithNewConsensusPayload sets NewConsensusPayload. -func WithNewConsensusPayload[H Hash, A Address](f func(*Context[H, A], MessageType, any) ConsensusPayload[H, A]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewConsensusPayload[H Hash](f func(*Context[H], MessageType, any) ConsensusPayload[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewConsensusPayload = f } } // WithNewPrepareRequest sets NewPrepareRequest. -func WithNewPrepareRequest[H Hash, A Address](f func(ts uint64, nonce uint64, nextConsensus A, transactionsHashes []H) PrepareRequest[H, A]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewPrepareRequest[H Hash](f func(ts uint64, nonce uint64, transactionsHashes []H) PrepareRequest[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewPrepareRequest = f } } // WithNewPrepareResponse sets NewPrepareResponse. -func WithNewPrepareResponse[H Hash, A Address](f func(preparationHash H) PrepareResponse[H]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewPrepareResponse[H Hash](f func(preparationHash H) PrepareResponse[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewPrepareResponse = f } } // WithNewChangeView sets NewChangeView. -func WithNewChangeView[H Hash, A Address](f func(byte, ChangeViewReason, uint64) ChangeView) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewChangeView[H Hash](f func(byte, ChangeViewReason, uint64) ChangeView) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewChangeView = f } } // WithNewCommit sets NewCommit. -func WithNewCommit[H Hash, A Address](f func([]byte) Commit) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewCommit[H Hash](f func([]byte) Commit) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewCommit = f } } // WithNewRecoveryRequest sets NewRecoveryRequest. -func WithNewRecoveryRequest[H Hash, A Address](f func(ts uint64) RecoveryRequest) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewRecoveryRequest[H Hash](f func(ts uint64) RecoveryRequest) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewRecoveryRequest = f } } // WithNewRecoveryMessage sets NewRecoveryMessage. -func WithNewRecoveryMessage[H Hash, A Address](f func() RecoveryMessage[H, A]) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithNewRecoveryMessage[H Hash](f func() RecoveryMessage[H]) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.NewRecoveryMessage = f } } // WithVerifyPrepareRequest sets VerifyPrepareRequest. -func WithVerifyPrepareRequest[H Hash, A Address](f func(ConsensusPayload[H, A]) error) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithVerifyPrepareRequest[H Hash](f func(ConsensusPayload[H]) error) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.VerifyPrepareRequest = f } } // WithVerifyPrepareResponse sets VerifyPrepareResponse. -func WithVerifyPrepareResponse[H Hash, A Address](f func(ConsensusPayload[H, A]) error) func(config *Config[H, A]) { - return func(cfg *Config[H, A]) { +func WithVerifyPrepareResponse[H Hash](f func(ConsensusPayload[H]) error) func(config *Config[H]) { + return func(cfg *Config[H]) { cfg.VerifyPrepareResponse = f } } diff --git a/consensus_message.go b/consensus_message.go index 7e72029f..d8859dea 100644 --- a/consensus_message.go +++ b/consensus_message.go @@ -1,7 +1,7 @@ package dbft // ConsensusMessage is an interface for generic dBFT message. -type ConsensusMessage[H Hash, A Address] interface { +type ConsensusMessage[H Hash] interface { // ViewNumber returns view number when this message was originated. ViewNumber() byte // Type returns type of this message. @@ -12,7 +12,7 @@ type ConsensusMessage[H Hash, A Address] interface { // GetChangeView returns payload as if it was ChangeView. GetChangeView() ChangeView // GetPrepareRequest returns payload as if it was PrepareRequest. - GetPrepareRequest() PrepareRequest[H, A] + GetPrepareRequest() PrepareRequest[H] // GetPrepareResponse returns payload as if it was PrepareResponse. GetPrepareResponse() PrepareResponse[H] // GetCommit returns payload as if it was Commit. @@ -20,5 +20,5 @@ type ConsensusMessage[H Hash, A Address] interface { // GetRecoveryRequest returns payload as if it was RecoveryRequest. GetRecoveryRequest() RecoveryRequest // GetRecoveryMessage returns payload as if it was RecoveryMessage. - GetRecoveryMessage() RecoveryMessage[H, A] + GetRecoveryMessage() RecoveryMessage[H] } diff --git a/consensus_payload.go b/consensus_payload.go index e537d3e0..c24699ef 100644 --- a/consensus_payload.go +++ b/consensus_payload.go @@ -2,8 +2,8 @@ package dbft // ConsensusPayload is a generic payload type which is exchanged // between the nodes. -type ConsensusPayload[H Hash, A Address] interface { - ConsensusMessage[H, A] +type ConsensusPayload[H Hash] interface { + ConsensusMessage[H] // ValidatorIndex returns index of validator from which // payload was originated from. diff --git a/context.go b/context.go index a6725649..15eb2b85 100644 --- a/context.go +++ b/context.go @@ -10,17 +10,17 @@ import ( // Context is a main dBFT structure which // contains all information needed for performing transitions. -type Context[H Hash, A Address] struct { +type Context[H Hash] struct { // Config is dBFT's Config instance. - Config *Config[H, A] + Config *Config[H] // Priv is node's private key. Priv PrivateKey // Pub is node's public key. Pub PublicKey - block Block[H, A] - header Block[H, A] + block Block[H] + header Block[H] // blockProcessed denotes whether Config.ProcessBlock callback was called for the current // height. If so, then no second call must happen. After new block is received by the user, // dBFT stops any new transaction or messages processing as far as timeouts handling till @@ -40,8 +40,6 @@ type Context[H Hash, A Address] struct { PrimaryIndex uint Version uint32 - // NextConsensus is a hash of the validators which will be accepting the next block. - NextConsensus A // PrevHash is a hash of the previous block. PrevHash H @@ -56,18 +54,18 @@ type Context[H Hash, A Address] struct { Transactions map[H]Transaction[H] // PreparationPayloads stores consensus Prepare* payloads for the current epoch. - PreparationPayloads []ConsensusPayload[H, A] + PreparationPayloads []ConsensusPayload[H] // CommitPayloads stores consensus Commit payloads sent throughout all epochs. It // is assumed that valid Commit payload can only be sent once by a single node per // the whole set of consensus epochs for particular block. Invalid commit payloads // are kicked off this list immediately (if PrepareRequest was received for the // current round, so it's possible to verify Commit against it) or stored till // the corresponding PrepareRequest receiving. - CommitPayloads []ConsensusPayload[H, A] + CommitPayloads []ConsensusPayload[H] // ChangeViewPayloads stores consensus ChangeView payloads for the current epoch. - ChangeViewPayloads []ConsensusPayload[H, A] + ChangeViewPayloads []ConsensusPayload[H] // LastChangeViewPayloads stores consensus ChangeView payloads for the last epoch. - LastChangeViewPayloads []ConsensusPayload[H, A] + LastChangeViewPayloads []ConsensusPayload[H] // LastSeenMessage array stores the height of the last seen message, for each validator. // if this node never heard from validator i, LastSeenMessage[i] will be -1. LastSeenMessage []*timer.HV @@ -78,16 +76,16 @@ type Context[H Hash, A Address] struct { } // N returns total number of validators. -func (c *Context[H, A]) N() int { return len(c.Validators) } +func (c *Context[H]) N() int { return len(c.Validators) } // F returns number of validators which can be faulty. -func (c *Context[H, A]) F() int { return (len(c.Validators) - 1) / 3 } +func (c *Context[H]) F() int { return (len(c.Validators) - 1) / 3 } // M returns number of validators which must function correctly. -func (c *Context[H, A]) M() int { return len(c.Validators) - c.F() } +func (c *Context[H]) M() int { return len(c.Validators) - c.F() } // GetPrimaryIndex returns index of a primary node for the specified view. -func (c *Context[H, A]) GetPrimaryIndex(viewNumber byte) uint { +func (c *Context[H]) GetPrimaryIndex(viewNumber byte) uint { p := (int(c.BlockIndex) - int(viewNumber)) % len(c.Validators) if p >= 0 { return uint(p) @@ -97,19 +95,19 @@ func (c *Context[H, A]) GetPrimaryIndex(viewNumber byte) uint { } // IsPrimary returns true iff node is primary for current height and view. -func (c *Context[H, A]) IsPrimary() bool { return c.MyIndex == int(c.PrimaryIndex) } +func (c *Context[H]) IsPrimary() bool { return c.MyIndex == int(c.PrimaryIndex) } // IsBackup returns true iff node is backup for current height and view. -func (c *Context[H, A]) IsBackup() bool { +func (c *Context[H]) IsBackup() bool { return c.MyIndex >= 0 && !c.IsPrimary() } // WatchOnly returns true iff node takes no active part in consensus. -func (c *Context[H, A]) WatchOnly() bool { return c.MyIndex < 0 || c.Config.WatchOnly() } +func (c *Context[H]) WatchOnly() bool { return c.MyIndex < 0 || c.Config.WatchOnly() } // CountCommitted returns number of received Commit messages not only for the current // epoch but also for any other epoch. -func (c *Context[H, A]) CountCommitted() (count int) { +func (c *Context[H]) CountCommitted() (count int) { for i := range c.CommitPayloads { if c.CommitPayloads[i] != nil { count++ @@ -121,7 +119,7 @@ func (c *Context[H, A]) CountCommitted() (count int) { // CountFailed returns number of nodes with which no communication was performed // for this view and that hasn't sent the Commit message at the previous views. -func (c *Context[H, A]) CountFailed() (count int) { +func (c *Context[H]) CountFailed() (count int) { for i, hv := range c.LastSeenMessage { if c.CommitPayloads[i] == nil && (hv == nil || hv.Height < c.BlockIndex || hv.View < c.ViewNumber) { count++ @@ -133,18 +131,18 @@ func (c *Context[H, A]) CountFailed() (count int) { // RequestSentOrReceived returns true iff PrepareRequest // was sent or received for the current epoch. -func (c *Context[H, A]) RequestSentOrReceived() bool { +func (c *Context[H]) RequestSentOrReceived() bool { return c.PreparationPayloads[c.PrimaryIndex] != nil } // ResponseSent returns true iff Prepare* message was sent for the current epoch. -func (c *Context[H, A]) ResponseSent() bool { +func (c *Context[H]) ResponseSent() bool { return !c.WatchOnly() && c.PreparationPayloads[c.MyIndex] != nil } // CommitSent returns true iff Commit message was sent for the current epoch // assuming that the node can't go further than current epoch after commit was sent. -func (c *Context[H, A]) CommitSent() bool { +func (c *Context[H]) CommitSent() bool { return !c.WatchOnly() && c.CommitPayloads[c.MyIndex] != nil } @@ -161,10 +159,10 @@ func (c *Context[H, A]) CommitSent() bool { // several places where the call to CreateBlock happens (one of them is right after // PrepareRequest receiving). Thus, we have a separate Context.blockProcessed field // for the described purpose. -func (c *Context[H, A]) BlockSent() bool { return c.blockProcessed } +func (c *Context[H]) BlockSent() bool { return c.blockProcessed } // ViewChanging returns true iff node is in a process of changing view. -func (c *Context[H, A]) ViewChanging() bool { +func (c *Context[H]) ViewChanging() bool { if c.WatchOnly() { return false } @@ -175,7 +173,7 @@ func (c *Context[H, A]) ViewChanging() bool { } // NotAcceptingPayloadsDueToViewChanging returns true if node should not accept new payloads. -func (c *Context[H, A]) NotAcceptingPayloadsDueToViewChanging() bool { +func (c *Context[H]) NotAcceptingPayloadsDueToViewChanging() bool { return c.ViewChanging() && !c.MoreThanFNodesCommittedOrLost() } @@ -186,11 +184,11 @@ func (c *Context[H, A]) NotAcceptingPayloadsDueToViewChanging() bool { // asking change views loses network or crashes and comes back when nodes are committed in more than one higher // numbered view, it is possible for the node accepting recovery to commit in any of the higher views, thus // potentially splitting nodes among views and stalling the network. -func (c *Context[H, A]) MoreThanFNodesCommittedOrLost() bool { +func (c *Context[H]) MoreThanFNodesCommittedOrLost() bool { return c.CountCommitted()+c.CountFailed() > c.F() } -func (c *Context[H, A]) reset(view byte, ts uint64) { +func (c *Context[H]) reset(view byte, ts uint64) { c.MyIndex = -1 c.lastBlockTimestamp = ts @@ -200,7 +198,7 @@ func (c *Context[H, A]) reset(view byte, ts uint64) { c.Validators = c.Config.GetValidators() n := len(c.Validators) - c.LastChangeViewPayloads = make([]ConsensusPayload[H, A], n) + c.LastChangeViewPayloads = make([]ConsensusPayload[H], n) if c.LastSeenMessage == nil { c.LastSeenMessage = make([]*timer.HV, n) @@ -223,11 +221,11 @@ func (c *Context[H, A]) reset(view byte, ts uint64) { c.header = nil n := len(c.Validators) - c.ChangeViewPayloads = make([]ConsensusPayload[H, A], n) + c.ChangeViewPayloads = make([]ConsensusPayload[H], n) if view == 0 { - c.CommitPayloads = make([]ConsensusPayload[H, A], n) + c.CommitPayloads = make([]ConsensusPayload[H], n) } - c.PreparationPayloads = make([]ConsensusPayload[H, A], n) + c.PreparationPayloads = make([]ConsensusPayload[H], n) c.Transactions = make(map[H]Transaction[H]) c.TransactionHashes = nil @@ -244,7 +242,7 @@ func (c *Context[H, A]) reset(view byte, ts uint64) { } // Fill initializes consensus when node is a speaker. -func (c *Context[H, A]) Fill() { +func (c *Context[H]) Fill() { b := make([]byte, 8) _, err := rand.Read(b) if err != nil { @@ -261,9 +259,6 @@ func (c *Context[H, A]) Fill() { c.Transactions[h] = txx[i] } - validators := c.Config.GetValidators(txx...) - c.NextConsensus = c.Config.GetConsensusAddress(validators...) - c.Timestamp = c.lastBlockTimestamp + c.Config.TimestampIncrement if now := c.getTimestamp(); now > c.Timestamp { c.Timestamp = now @@ -272,12 +267,12 @@ func (c *Context[H, A]) Fill() { // getTimestamp returns nanoseconds-precision timestamp using // current context config. -func (c *Context[H, A]) getTimestamp() uint64 { +func (c *Context[H]) getTimestamp() uint64 { return uint64(c.Config.Timer.Now().UnixNano()) / c.Config.TimestampIncrement * c.Config.TimestampIncrement } // CreateBlock returns resulting block for the current epoch. -func (c *Context[H, A]) CreateBlock() Block[H, A] { +func (c *Context[H]) CreateBlock() Block[H] { if c.block == nil { if c.block = c.MakeHeader(); c.block == nil { return nil @@ -297,7 +292,7 @@ func (c *Context[H, A]) CreateBlock() Block[H, A] { // MakeHeader returns half-filled block for the current epoch. // All hashable fields will be filled. -func (c *Context[H, A]) MakeHeader() Block[H, A] { +func (c *Context[H]) MakeHeader() Block[H] { if c.header == nil { if !c.RequestSentOrReceived() { return nil @@ -310,6 +305,6 @@ func (c *Context[H, A]) MakeHeader() Block[H, A] { // hasAllTransactions returns true iff all transactions were received // for the proposed block. -func (c *Context[H, A]) hasAllTransactions() bool { +func (c *Context[H]) hasAllTransactions() bool { return len(c.TransactionHashes) == len(c.Transactions) } diff --git a/dbft.go b/dbft.go index 2fec0cd8..26a33cb4 100644 --- a/dbft.go +++ b/dbft.go @@ -13,12 +13,12 @@ type ( // and [Config] (service configuration). Data exposed from these fields // is supposed to be read-only, state is changed via methods of this // structure. - DBFT[H Hash, A Address] struct { - Context[H, A] - Config[H, A] + DBFT[H Hash] struct { + Context[H] + Config[H] *sync.Mutex - cache cache[H, A] + cache cache[H] recovering bool } ) @@ -27,8 +27,8 @@ type ( // using provided options or nil if some of the options are missing or invalid. // H and A generic parameters are used as hash and address representation for // dBFT consensus messages, blocks and transactions. -func New[H Hash, A Address](options ...func(config *Config[H, A])) *DBFT[H, A] { - cfg := defaultConfig[H, A]() +func New[H Hash](options ...func(config *Config[H])) *DBFT[H] { + cfg := defaultConfig[H]() for _, option := range options { option(cfg) @@ -38,10 +38,10 @@ func New[H Hash, A Address](options ...func(config *Config[H, A])) *DBFT[H, A] { return nil } - d := &DBFT[H, A]{ + d := &DBFT[H]{ Mutex: new(sync.Mutex), Config: *cfg, - Context: Context[H, A]{ + Context: Context[H]{ Config: cfg, }, } @@ -49,7 +49,7 @@ func New[H Hash, A Address](options ...func(config *Config[H, A])) *DBFT[H, A] { return d } -func (d *DBFT[H, A]) addTransaction(tx Transaction[H]) { +func (d *DBFT[H]) addTransaction(tx Transaction[H]) { d.Transactions[tx.Hash()] = tx if d.hasAllTransactions() { if d.IsPrimary() || d.Context.WatchOnly() { @@ -69,8 +69,8 @@ func (d *DBFT[H, A]) addTransaction(tx Transaction[H]) { // Start initializes dBFT instance and starts the protocol if node is primary. // It accepts the timestamp of the previous block. It should be called once // per DBFT lifetime. -func (d *DBFT[H, A]) Start(ts uint64) { - d.cache = newCache[H, A]() +func (d *DBFT[H]) Start(ts uint64) { + d.cache = newCache[H]() d.initializeConsensus(0, ts) d.start() } @@ -80,11 +80,11 @@ func (d *DBFT[H, A]) Start(ts uint64) { // after new block is processed by ledger (the block can come from dBFT or be // received by other means). The height is to be derived from the configured // CurrentHeight callback and view will be set to 0. -func (d *DBFT[H, A]) Reset(ts uint64) { +func (d *DBFT[H]) Reset(ts uint64) { d.initializeConsensus(0, ts) } -func (d *DBFT[H, A]) initializeConsensus(view byte, ts uint64) { +func (d *DBFT[H]) initializeConsensus(view byte, ts uint64) { d.reset(view, ts) var role string @@ -137,7 +137,7 @@ func (d *DBFT[H, A]) initializeConsensus(view byte, ts uint64) { } // OnTransaction notifies service about receiving new transaction. -func (d *DBFT[H, A]) OnTransaction(tx Transaction[H]) { +func (d *DBFT[H]) OnTransaction(tx Transaction[H]) { // d.Logger.Debug("OnTransaction", // zap.Bool("backup", d.IsBackup()), // zap.Bool("not_accepting", d.NotAcceptingPayloadsDueToViewChanging()), @@ -169,7 +169,7 @@ func (d *DBFT[H, A]) OnTransaction(tx Transaction[H]) { } // OnTimeout advances state machine as if timeout was fired. -func (d *DBFT[H, A]) OnTimeout(hv timer.HV) { +func (d *DBFT[H]) OnTimeout(hv timer.HV) { if d.Context.WatchOnly() || d.BlockSent() { return } @@ -200,7 +200,7 @@ func (d *DBFT[H, A]) OnTimeout(hv timer.HV) { } // OnReceive advances state machine in accordance with msg. -func (d *DBFT[H, A]) OnReceive(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) OnReceive(msg ConsensusPayload[H]) { if int(msg.ValidatorIndex()) >= len(d.Validators) { d.Logger.Error("too big validator index", zap.Uint16("from", msg.ValidatorIndex())) return @@ -269,7 +269,7 @@ func (d *DBFT[H, A]) OnReceive(msg ConsensusPayload[H, A]) { // start performs initial operations and returns messages to be sent. // It must be called after every height or view increment. -func (d *DBFT[H, A]) start() { +func (d *DBFT[H]) start() { if !d.IsPrimary() { if msgs := d.cache.getHeight(d.BlockIndex); msgs != nil { for _, m := range msgs.prepare { @@ -291,7 +291,7 @@ func (d *DBFT[H, A]) start() { d.sendPrepareRequest() } -func (d *DBFT[H, A]) onPrepareRequest(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onPrepareRequest(msg ConsensusPayload[H]) { // ignore prepareRequest if we had already received it or // are in process of changing view if d.RequestSentOrReceived() { //|| (d.ViewChanging() && !d.MoreThanFNodesCommittedOrLost()) { @@ -327,7 +327,6 @@ func (d *DBFT[H, A]) onPrepareRequest(msg ConsensusPayload[H, A]) { d.Timestamp = p.Timestamp() d.Nonce = p.Nonce() - d.NextConsensus = p.NextConsensus() d.TransactionHashes = p.TransactionHashes() d.Logger.Info("received PrepareRequest", zap.Uint16("validator", msg.ValidatorIndex()), zap.Int("tx", len(d.TransactionHashes))) @@ -343,7 +342,7 @@ func (d *DBFT[H, A]) onPrepareRequest(msg ConsensusPayload[H, A]) { d.checkPrepare() } -func (d *DBFT[H, A]) processMissingTx() { +func (d *DBFT[H]) processMissingTx() { missing := make([]H, 0, len(d.TransactionHashes)/2) for _, h := range d.TransactionHashes { @@ -369,16 +368,7 @@ func (d *DBFT[H, A]) processMissingTx() { // the new proposed block, if it's fine it returns true, if something is wrong // with it, it sends a changeView request and returns false. It's only valid to // call it when all transactions for this block are already collected. -func (d *DBFT[H, A]) createAndCheckBlock() bool { - txx := make([]Transaction[H], 0, len(d.TransactionHashes)) - for _, h := range d.TransactionHashes { - txx = append(txx, d.Transactions[h]) - } - if d.NextConsensus != d.GetConsensusAddress(d.GetValidators(txx...)...) { - d.Logger.Error("invalid nextConsensus in proposed block") - d.sendChangeView(CVBlockRejectedByPolicy) - return false - } +func (d *DBFT[H]) createAndCheckBlock() bool { if b := d.Context.CreateBlock(); !d.VerifyBlock(b) { d.Logger.Warn("proposed block fails verification") d.sendChangeView(CVTxInvalid) @@ -387,7 +377,7 @@ func (d *DBFT[H, A]) createAndCheckBlock() bool { return true } -func (d *DBFT[H, A]) updateExistingPayloads(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) updateExistingPayloads(msg ConsensusPayload[H]) { for i, m := range d.PreparationPayloads { if m != nil && m.Type() == PrepareResponseType { resp := m.GetPrepareResponse() @@ -410,7 +400,7 @@ func (d *DBFT[H, A]) updateExistingPayloads(msg ConsensusPayload[H, A]) { } } -func (d *DBFT[H, A]) onPrepareResponse(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onPrepareResponse(msg ConsensusPayload[H]) { if d.ViewNumber != msg.ViewNumber() { d.Logger.Debug("ignoring wrong view number", zap.Uint("view", uint(msg.ViewNumber()))) return @@ -462,7 +452,7 @@ func (d *DBFT[H, A]) onPrepareResponse(msg ConsensusPayload[H, A]) { } } -func (d *DBFT[H, A]) onChangeView(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onChangeView(msg ConsensusPayload[H]) { p := msg.GetChangeView() if p.NewViewNumber() <= d.ViewNumber { @@ -493,7 +483,7 @@ func (d *DBFT[H, A]) onChangeView(msg ConsensusPayload[H, A]) { d.checkChangeView(p.NewViewNumber()) } -func (d *DBFT[H, A]) onCommit(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onCommit(msg ConsensusPayload[H]) { existing := d.CommitPayloads[msg.ValidatorIndex()] if existing != nil { if existing.Hash() != msg.Hash() { @@ -535,7 +525,7 @@ func (d *DBFT[H, A]) onCommit(msg ConsensusPayload[H, A]) { d.CommitPayloads[msg.ValidatorIndex()] = msg } -func (d *DBFT[H, A]) onRecoveryRequest(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onRecoveryRequest(msg ConsensusPayload[H]) { if !d.CommitSent() { // Limit recoveries to be sent from no more than F nodes // TODO replace loop with a single if @@ -557,7 +547,7 @@ func (d *DBFT[H, A]) onRecoveryRequest(msg ConsensusPayload[H, A]) { d.sendRecoveryMessage() } -func (d *DBFT[H, A]) onRecoveryMessage(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) onRecoveryMessage(msg ConsensusPayload[H]) { d.Logger.Debug("recovery message received", zap.Any("dump", msg)) var ( @@ -617,7 +607,7 @@ func (d *DBFT[H, A]) onRecoveryMessage(msg ConsensusPayload[H, A]) { } } -func (d *DBFT[H, A]) changeTimer(delay time.Duration) { +func (d *DBFT[H]) changeTimer(delay time.Duration) { d.Logger.Debug("reset timer", zap.Uint32("h", d.BlockIndex), zap.Int("v", int(d.ViewNumber)), @@ -625,7 +615,7 @@ func (d *DBFT[H, A]) changeTimer(delay time.Duration) { d.Timer.Reset(timer.HV{Height: d.BlockIndex, View: d.ViewNumber}, delay) } -func (d *DBFT[H, A]) extendTimer(count time.Duration) { +func (d *DBFT[H]) extendTimer(count time.Duration) { if !d.CommitSent() && !d.ViewChanging() { d.Timer.Extend(count * d.SecondsPerBlock / time.Duration(d.M())) } @@ -633,6 +623,6 @@ func (d *DBFT[H, A]) extendTimer(count time.Duration) { // Header returns current header from context. May be nil in case if no // header is constructed yet. Do not change the resulting header. -func (d *DBFT[H, A]) Header() Block[H, A] { +func (d *DBFT[H]) Header() Block[H] { return d.header } diff --git a/dbft_test.go b/dbft_test.go index abd7a056..48209e9d 100644 --- a/dbft_test.go +++ b/dbft_test.go @@ -15,7 +15,7 @@ import ( "go.uber.org/zap" ) -type Payload = dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] +type Payload = dbft.ConsensusPayload[crypto.Uint256] type testState struct { myIndex int @@ -26,8 +26,8 @@ type testState struct { currHeight uint32 currHash crypto.Uint256 pool *testPool - blocks []dbft.Block[crypto.Uint256, crypto.Uint160] - verify func(b dbft.Block[crypto.Uint256, crypto.Uint160]) bool + blocks []dbft.Block[crypto.Uint256] + verify func(b dbft.Block[crypto.Uint256]) bool } type ( @@ -44,7 +44,7 @@ func TestDBFT_OnStartPrimarySendPrepareRequest(t *testing.T) { t.Run("backup sends nothing on start", func(t *testing.T) { s.currHeight = 0 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) require.Nil(t, s.tryRecv()) @@ -52,7 +52,7 @@ func TestDBFT_OnStartPrimarySendPrepareRequest(t *testing.T) { t.Run("primary send PrepareRequest on start", func(t *testing.T) { s.currHeight = 1 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) p := s.tryRecv() @@ -91,7 +91,7 @@ func TestDBFT_SingleNode(t *testing.T) { s := newTestState(0, 1) s.currHeight = 2 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) p := s.tryRecv() @@ -117,7 +117,7 @@ func TestDBFT_SingleNode(t *testing.T) { func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { s := newTestState(2, 7) - s.verify = func(b dbft.Block[crypto.Uint256, crypto.Uint160]) bool { + s.verify = func(b dbft.Block[crypto.Uint256]) bool { for _, tx := range b.Transactions() { if tx.(testTx)%10 == 0 { return false @@ -129,7 +129,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { t.Run("receive request from primary", func(t *testing.T) { s.currHeight = 4 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) txs := []testTx{1} s.pool.Add(txs[0]) @@ -161,7 +161,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { t.Run("change view on invalid tx", func(t *testing.T) { s.currHeight = 4 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) txs := []testTx{10} service.Start(0) @@ -189,7 +189,7 @@ func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) { t.Run("receive invalid prepare request", func(t *testing.T) { s.currHeight = 4 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) txs := []testTx{1, 2} s.pool.Add(txs[0]) @@ -237,7 +237,7 @@ func TestDBFT_CommitOnTransaction(t *testing.T) { s := newTestState(0, 4) s.currHeight = 1 - srv := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + srv := dbft.New[crypto.Uint256](s.getOptions()...) srv.Start(0) require.Nil(t, s.tryRecv()) @@ -257,7 +257,7 @@ func TestDBFT_CommitOnTransaction(t *testing.T) { privs: s.privs, } s1.pool.Add(tx) - srv1 := dbft.New[crypto.Uint256, crypto.Uint160](s1.getOptions()...) + srv1 := dbft.New[crypto.Uint256](s1.getOptions()...) srv1.Start(0) srv1.OnReceive(req) srv1.OnReceive(s1.getPrepareResponse(1, req.Hash())) @@ -279,7 +279,7 @@ func TestDBFT_OnReceiveCommit(t *testing.T) { s := newTestState(2, 4) t.Run("send commit after enough responses", func(t *testing.T) { s.currHeight = 1 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) req := s.tryRecv() @@ -339,7 +339,7 @@ func TestDBFT_OnReceiveRecoveryRequest(t *testing.T) { s := newTestState(2, 4) t.Run("send recovery message", func(t *testing.T) { s.currHeight = 1 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) req := s.tryRecv() @@ -361,7 +361,7 @@ func TestDBFT_OnReceiveRecoveryRequest(t *testing.T) { require.Equal(t, dbft.RecoveryMessageType, rm.Type()) other := s.copyWithIndex(3) - srv2 := dbft.New[crypto.Uint256, crypto.Uint160](other.getOptions()...) + srv2 := dbft.New[crypto.Uint256](other.getOptions()...) srv2.Start(0) srv2.OnReceive(rm) @@ -384,7 +384,7 @@ func TestDBFT_OnReceiveChangeView(t *testing.T) { s := newTestState(2, 4) t.Run("change view correctly", func(t *testing.T) { s.currHeight = 6 - service := dbft.New[crypto.Uint256, crypto.Uint160](s.getOptions()...) + service := dbft.New[crypto.Uint256](s.getOptions()...) service.Start(0) resp := s.getChangeView(1, 1) @@ -411,92 +411,85 @@ func TestDBFT_OnReceiveChangeView(t *testing.T) { func TestDBFT_Invalid(t *testing.T) { t.Run("without keys", func(t *testing.T) { - require.Nil(t, dbft.New[crypto.Uint256, crypto.Uint160]()) + require.Nil(t, dbft.New[crypto.Uint256]()) }) priv, pub := crypto.Generate(rand.Reader) require.NotNil(t, priv) require.NotNil(t, pub) - opts := []func(*dbft.Config[crypto.Uint256, crypto.Uint160]){dbft.WithKeyPair[crypto.Uint256, crypto.Uint160](priv, pub)} + opts := []func(*dbft.Config[crypto.Uint256]){dbft.WithKeyPair[crypto.Uint256](priv, pub)} t.Run("without CurrentHeight", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithCurrentHeight[crypto.Uint256, crypto.Uint160](func() uint32 { return 0 })) + opts = append(opts, dbft.WithCurrentHeight[crypto.Uint256](func() uint32 { return 0 })) t.Run("without CurrentBlockHash", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithCurrentBlockHash[crypto.Uint256, crypto.Uint160](func() crypto.Uint256 { return crypto.Uint256{} })) + opts = append(opts, dbft.WithCurrentBlockHash[crypto.Uint256](func() crypto.Uint256 { return crypto.Uint256{} })) t.Run("without GetValidators", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithGetValidators[crypto.Uint256, crypto.Uint160](func(...dbft.Transaction[crypto.Uint256]) []dbft.PublicKey { + opts = append(opts, dbft.WithGetValidators[crypto.Uint256](func(...dbft.Transaction[crypto.Uint256]) []dbft.PublicKey { return []dbft.PublicKey{pub} })) t.Run("without NewBlockFromContext", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewBlockFromContext[crypto.Uint256, crypto.Uint160](func(_ *dbft.Context[crypto.Uint256, crypto.Uint160]) dbft.Block[crypto.Uint256, crypto.Uint160] { + opts = append(opts, dbft.WithNewBlockFromContext[crypto.Uint256](func(_ *dbft.Context[crypto.Uint256]) dbft.Block[crypto.Uint256] { return nil })) - t.Run("without GetConsensusAddress", func(t *testing.T) { - require.Nil(t, dbft.New(opts...)) - }) - - opts = append(opts, dbft.WithGetConsensusAddress[crypto.Uint256, crypto.Uint160](func(_ ...dbft.PublicKey) crypto.Uint160 { - return crypto.Uint160{} - })) t.Run("without NewConsensusPayload", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewConsensusPayload[crypto.Uint256, crypto.Uint160](func(_ *dbft.Context[crypto.Uint256, crypto.Uint160], _ dbft.MessageType, _ any) dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { + opts = append(opts, dbft.WithNewConsensusPayload[crypto.Uint256](func(_ *dbft.Context[crypto.Uint256], _ dbft.MessageType, _ any) dbft.ConsensusPayload[crypto.Uint256] { return nil })) t.Run("without NewPrepareRequest", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewPrepareRequest[crypto.Uint256, crypto.Uint160](func(uint64, uint64, crypto.Uint160, []crypto.Uint256) dbft.PrepareRequest[crypto.Uint256, crypto.Uint160] { + opts = append(opts, dbft.WithNewPrepareRequest[crypto.Uint256](func(uint64, uint64, []crypto.Uint256) dbft.PrepareRequest[crypto.Uint256] { return nil })) t.Run("without NewPrepareResponse", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewPrepareResponse[crypto.Uint256, crypto.Uint160](func(crypto.Uint256) dbft.PrepareResponse[crypto.Uint256] { + opts = append(opts, dbft.WithNewPrepareResponse[crypto.Uint256](func(crypto.Uint256) dbft.PrepareResponse[crypto.Uint256] { return nil })) t.Run("without NewChangeView", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewChangeView[crypto.Uint256, crypto.Uint160](func(byte, dbft.ChangeViewReason, uint64) dbft.ChangeView { + opts = append(opts, dbft.WithNewChangeView[crypto.Uint256](func(byte, dbft.ChangeViewReason, uint64) dbft.ChangeView { return nil })) t.Run("without NewCommit", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewCommit[crypto.Uint256, crypto.Uint160](func([]byte) dbft.Commit { + opts = append(opts, dbft.WithNewCommit[crypto.Uint256](func([]byte) dbft.Commit { return nil })) t.Run("without NewRecoveryRequest", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewRecoveryRequest[crypto.Uint256, crypto.Uint160](func(uint64) dbft.RecoveryRequest { + opts = append(opts, dbft.WithNewRecoveryRequest[crypto.Uint256](func(uint64) dbft.RecoveryRequest { return nil })) t.Run("without NewRecoveryMessage", func(t *testing.T) { require.Nil(t, dbft.New(opts...)) }) - opts = append(opts, dbft.WithNewRecoveryMessage[crypto.Uint256, crypto.Uint160](func() dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] { + opts = append(opts, dbft.WithNewRecoveryMessage[crypto.Uint256](func() dbft.RecoveryMessage[crypto.Uint256] { return nil })) t.Run("with all defaults", func(t *testing.T) { @@ -529,19 +522,19 @@ func TestDBFT_Invalid(t *testing.T) { func TestDBFT_FourGoodNodesDeadlock(t *testing.T) { r0 := newTestState(0, 4) r0.currHeight = 4 - s0 := dbft.New[crypto.Uint256, crypto.Uint160](r0.getOptions()...) + s0 := dbft.New[crypto.Uint256](r0.getOptions()...) s0.Start(0) r1 := r0.copyWithIndex(1) - s1 := dbft.New[crypto.Uint256, crypto.Uint160](r1.getOptions()...) + s1 := dbft.New[crypto.Uint256](r1.getOptions()...) s1.Start(0) r2 := r0.copyWithIndex(2) - s2 := dbft.New[crypto.Uint256, crypto.Uint160](r2.getOptions()...) + s2 := dbft.New[crypto.Uint256](r2.getOptions()...) s2.Start(0) r3 := r0.copyWithIndex(3) - s3 := dbft.New[crypto.Uint256, crypto.Uint160](r3.getOptions()...) + s3 := dbft.New[crypto.Uint256](r3.getOptions()...) s3.Start(0) // Step 1. The primary (at view 0) replica 1 sends the PrepareRequest message. @@ -760,7 +753,7 @@ func (s testState) getPrepareRequest(from uint16, hashes ...crypto.Uint256) Payl } func (s testState) getPrepareRequestWithHeight(from uint16, height uint32, hashes ...crypto.Uint256) Payload { - req := payload.NewPrepareRequest(0, 0, s.nextConsensus(), hashes) + req := payload.NewPrepareRequest(0, 0, hashes) p := payload.NewConsensusPayload(dbft.PrepareRequestType, height, from, 0, req) return p @@ -789,7 +782,7 @@ func (s *testState) tryRecv() Payload { return p } -func (s *testState) nextBlock() dbft.Block[crypto.Uint256, crypto.Uint160] { +func (s *testState) nextBlock() dbft.Block[crypto.Uint256] { if len(s.blocks) == 0 { return nil } @@ -812,43 +805,38 @@ func (s testState) copyWithIndex(myIndex int) *testState { } } -func (s testState) nextConsensus(...dbft.PublicKey) crypto.Uint160 { - return crypto.Uint160{1} -} - -func (s *testState) getOptions() []func(*dbft.Config[crypto.Uint256, crypto.Uint160]) { - opts := []func(*dbft.Config[crypto.Uint256, crypto.Uint160]){ - dbft.WithCurrentHeight[crypto.Uint256, crypto.Uint160](func() uint32 { return s.currHeight }), - dbft.WithCurrentBlockHash[crypto.Uint256, crypto.Uint160](func() crypto.Uint256 { return s.currHash }), - dbft.WithGetValidators[crypto.Uint256, crypto.Uint160](func(...dbft.Transaction[crypto.Uint256]) []dbft.PublicKey { return s.pubs }), - dbft.WithKeyPair[crypto.Uint256, crypto.Uint160](s.privs[s.myIndex], s.pubs[s.myIndex]), - dbft.WithBroadcast[crypto.Uint256, crypto.Uint160](func(p Payload) { s.ch = append(s.ch, p) }), - dbft.WithGetTx[crypto.Uint256, crypto.Uint160](s.pool.Get), - dbft.WithProcessBlock[crypto.Uint256, crypto.Uint160](func(b dbft.Block[crypto.Uint256, crypto.Uint160]) { s.blocks = append(s.blocks, b) }), - dbft.WithGetConsensusAddress[crypto.Uint256, crypto.Uint160](s.nextConsensus), - dbft.WithWatchOnly[crypto.Uint256, crypto.Uint160](func() bool { return false }), - dbft.WithGetBlock[crypto.Uint256, crypto.Uint160](func(crypto.Uint256) dbft.Block[crypto.Uint256, crypto.Uint160] { return nil }), - dbft.WithTimer[crypto.Uint256, crypto.Uint160](timer.New()), - dbft.WithLogger[crypto.Uint256, crypto.Uint160](zap.NewNop()), - dbft.WithNewBlockFromContext[crypto.Uint256, crypto.Uint160](newBlockFromContext), - dbft.WithSecondsPerBlock[crypto.Uint256, crypto.Uint160](time.Second * 10), - dbft.WithRequestTx[crypto.Uint256, crypto.Uint160](func(...crypto.Uint256) {}), - dbft.WithGetVerified[crypto.Uint256, crypto.Uint160](func() []dbft.Transaction[crypto.Uint256] { return []dbft.Transaction[crypto.Uint256]{} }), - - dbft.WithNewConsensusPayload[crypto.Uint256, crypto.Uint160](newConsensusPayload), - dbft.WithNewPrepareRequest[crypto.Uint256, crypto.Uint160](payload.NewPrepareRequest), - dbft.WithNewPrepareResponse[crypto.Uint256, crypto.Uint160](payload.NewPrepareResponse), - dbft.WithNewChangeView[crypto.Uint256, crypto.Uint160](payload.NewChangeView), - dbft.WithNewCommit[crypto.Uint256, crypto.Uint160](payload.NewCommit), - dbft.WithNewRecoveryRequest[crypto.Uint256, crypto.Uint160](payload.NewRecoveryRequest), - dbft.WithNewRecoveryMessage[crypto.Uint256, crypto.Uint160](func() dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] { +func (s *testState) getOptions() []func(*dbft.Config[crypto.Uint256]) { + opts := []func(*dbft.Config[crypto.Uint256]){ + dbft.WithCurrentHeight[crypto.Uint256](func() uint32 { return s.currHeight }), + dbft.WithCurrentBlockHash[crypto.Uint256](func() crypto.Uint256 { return s.currHash }), + dbft.WithGetValidators[crypto.Uint256](func(...dbft.Transaction[crypto.Uint256]) []dbft.PublicKey { return s.pubs }), + dbft.WithKeyPair[crypto.Uint256](s.privs[s.myIndex], s.pubs[s.myIndex]), + dbft.WithBroadcast[crypto.Uint256](func(p Payload) { s.ch = append(s.ch, p) }), + dbft.WithGetTx[crypto.Uint256](s.pool.Get), + dbft.WithProcessBlock[crypto.Uint256](func(b dbft.Block[crypto.Uint256]) { s.blocks = append(s.blocks, b) }), + dbft.WithWatchOnly[crypto.Uint256](func() bool { return false }), + dbft.WithGetBlock[crypto.Uint256](func(crypto.Uint256) dbft.Block[crypto.Uint256] { return nil }), + dbft.WithTimer[crypto.Uint256](timer.New()), + dbft.WithLogger[crypto.Uint256](zap.NewNop()), + dbft.WithNewBlockFromContext[crypto.Uint256](newBlockFromContext), + dbft.WithSecondsPerBlock[crypto.Uint256](time.Second * 10), + dbft.WithRequestTx[crypto.Uint256](func(...crypto.Uint256) {}), + dbft.WithGetVerified[crypto.Uint256](func() []dbft.Transaction[crypto.Uint256] { return []dbft.Transaction[crypto.Uint256]{} }), + + dbft.WithNewConsensusPayload[crypto.Uint256](newConsensusPayload), + dbft.WithNewPrepareRequest[crypto.Uint256](payload.NewPrepareRequest), + dbft.WithNewPrepareResponse[crypto.Uint256](payload.NewPrepareResponse), + dbft.WithNewChangeView[crypto.Uint256](payload.NewChangeView), + dbft.WithNewCommit[crypto.Uint256](payload.NewCommit), + dbft.WithNewRecoveryRequest[crypto.Uint256](payload.NewRecoveryRequest), + dbft.WithNewRecoveryMessage[crypto.Uint256](func() dbft.RecoveryMessage[crypto.Uint256] { return payload.NewRecoveryMessage(nil) }), } verify := s.verify if verify == nil { - verify = func(dbft.Block[crypto.Uint256, crypto.Uint160]) bool { return true } + verify = func(dbft.Block[crypto.Uint256]) bool { return true } } opts = append(opts, dbft.WithVerifyBlock(verify)) @@ -857,23 +845,23 @@ func (s *testState) getOptions() []func(*dbft.Config[crypto.Uint256, crypto.Uint cfg := zap.NewDevelopmentConfig() cfg.DisableStacktrace = true logger, _ := cfg.Build() - opts = append(opts, dbft.WithLogger[crypto.Uint256, crypto.Uint160](logger)) + opts = append(opts, dbft.WithLogger[crypto.Uint256](logger)) } return opts } -func newBlockFromContext(ctx *dbft.Context[crypto.Uint256, crypto.Uint160]) dbft.Block[crypto.Uint256, crypto.Uint160] { +func newBlockFromContext(ctx *dbft.Context[crypto.Uint256]) dbft.Block[crypto.Uint256] { if ctx.TransactionHashes == nil { return nil } - block := block.NewBlock(ctx.Timestamp, ctx.BlockIndex, ctx.NextConsensus, ctx.PrevHash, ctx.Version, ctx.Nonce, ctx.TransactionHashes) + block := block.NewBlock(ctx.Timestamp, ctx.BlockIndex, ctx.PrevHash, ctx.Version, ctx.Nonce, ctx.TransactionHashes) return block } // newConsensusPayload is a function for creating consensus payload of specific // type. -func newConsensusPayload(c *dbft.Context[crypto.Uint256, crypto.Uint160], t dbft.MessageType, msg any) dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { +func newConsensusPayload(c *dbft.Context[crypto.Uint256], t dbft.MessageType, msg any) dbft.ConsensusPayload[crypto.Uint256] { cp := payload.NewConsensusPayload(t, c.BlockIndex, uint16(c.MyIndex), c.ViewNumber, msg) return cp } diff --git a/helpers.go b/helpers.go index eff55904..21f34e32 100644 --- a/helpers.go +++ b/helpers.go @@ -2,34 +2,34 @@ package dbft type ( // inbox is a structure storing messages from a single epoch. - inbox[H Hash, A Address] struct { - prepare map[uint16]ConsensusPayload[H, A] - chViews map[uint16]ConsensusPayload[H, A] - commit map[uint16]ConsensusPayload[H, A] + inbox[H Hash] struct { + prepare map[uint16]ConsensusPayload[H] + chViews map[uint16]ConsensusPayload[H] + commit map[uint16]ConsensusPayload[H] } // cache is an auxiliary structure storing messages // from future epochs. - cache[H Hash, A Address] struct { - mail map[uint32]*inbox[H, A] + cache[H Hash] struct { + mail map[uint32]*inbox[H] } ) -func newInbox[H Hash, A Address]() *inbox[H, A] { - return &inbox[H, A]{ - prepare: make(map[uint16]ConsensusPayload[H, A]), - chViews: make(map[uint16]ConsensusPayload[H, A]), - commit: make(map[uint16]ConsensusPayload[H, A]), +func newInbox[H Hash]() *inbox[H] { + return &inbox[H]{ + prepare: make(map[uint16]ConsensusPayload[H]), + chViews: make(map[uint16]ConsensusPayload[H]), + commit: make(map[uint16]ConsensusPayload[H]), } } -func newCache[H Hash, A Address]() cache[H, A] { - return cache[H, A]{ - mail: make(map[uint32]*inbox[H, A]), +func newCache[H Hash]() cache[H] { + return cache[H]{ + mail: make(map[uint32]*inbox[H]), } } -func (c *cache[H, A]) getHeight(h uint32) *inbox[H, A] { +func (c *cache[H]) getHeight(h uint32) *inbox[H] { if m, ok := c.mail[h]; ok { delete(c.mail, h) return m @@ -38,10 +38,10 @@ func (c *cache[H, A]) getHeight(h uint32) *inbox[H, A] { return nil } -func (c *cache[H, A]) addMessage(m ConsensusPayload[H, A]) { +func (c *cache[H]) addMessage(m ConsensusPayload[H]) { msgs, ok := c.mail[m.Height()] if !ok { - msgs = newInbox[H, A]() + msgs = newInbox[H]() c.mail[m.Height()] = msgs } diff --git a/helpers_test.go b/helpers_test.go index a24f86db..33a60920 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -9,7 +9,6 @@ import ( // Structures used for type-specific dBFT/payloads implementation to avoid cyclic // dependency. type ( - address struct{} hash struct{} payloadStub struct { height uint32 @@ -22,10 +21,6 @@ func (hash) String() string { return "" } -func (address) String() string { - return "" -} - func (p payloadStub) ViewNumber() byte { panic("TODO") } @@ -47,7 +42,7 @@ func (p payloadStub) SetPayload(any) { func (p payloadStub) GetChangeView() ChangeView { panic("TODO") } -func (p payloadStub) GetPrepareRequest() PrepareRequest[hash, address] { +func (p payloadStub) GetPrepareRequest() PrepareRequest[hash] { panic("TODO") } func (p payloadStub) GetPrepareResponse() PrepareResponse[hash] { @@ -59,7 +54,7 @@ func (p payloadStub) GetCommit() Commit { func (p payloadStub) GetRecoveryRequest() RecoveryRequest { panic("TODO") } -func (p payloadStub) GetRecoveryMessage() RecoveryMessage[hash, address] { +func (p payloadStub) GetRecoveryMessage() RecoveryMessage[hash] { panic("TODO") } func (p payloadStub) ValidatorIndex() uint16 { @@ -79,7 +74,7 @@ func (p payloadStub) Hash() hash { } func TestMessageCache(t *testing.T) { - c := newCache[hash, address]() + c := newCache[hash]() p1 := payloadStub{ height: 3, diff --git a/identity.go b/identity.go index 420dc361..8ab67b81 100644 --- a/identity.go +++ b/identity.go @@ -31,14 +31,4 @@ type ( comparable fmt.Stringer } - - // Address is a generic address interface used by dbft for operations related - // to consensus address. It is recommended to implement this interface - // using hash functions with low hash collision probability. The following - // requirements must be met: - // 1. Addresses of two equal sets of consensus members are equal. - // 2. Addresses of two different sets of consensus members are different. - Address interface { - comparable - } ) diff --git a/internal/block/block.go b/internal/block/block.go index 19940e7d..ddbf4266 100644 --- a/internal/block/block.go +++ b/internal/block/block.go @@ -52,11 +52,6 @@ func (b *neoBlock) Index() uint32 { return b.base.Index } -// NextConsensus implements Block interface. -func (b *neoBlock) NextConsensus() crypto.Uint160 { - return b.base.NextConsensus -} - // MerkleRoot implements Block interface. func (b *neoBlock) MerkleRoot() crypto.Uint256 { return b.base.MerkleRoot @@ -78,11 +73,14 @@ func (b *neoBlock) SetTransactions(txx []dbft.Transaction[crypto.Uint256]) { } // NewBlock returns new block. -func NewBlock(timestamp uint64, index uint32, nextConsensus crypto.Uint160, prevHash crypto.Uint256, version uint32, nonce uint64, txHashes []crypto.Uint256) dbft.Block[crypto.Uint256, crypto.Uint160] { +func NewBlock(timestamp uint64, index uint32, prevHash crypto.Uint256, version uint32, nonce uint64, txHashes []crypto.Uint256) dbft.Block[crypto.Uint256] { block := new(neoBlock) block.base.Timestamp = uint32(timestamp / 1000000000) block.base.Index = index - block.base.NextConsensus = nextConsensus + // NextConsensus information is not provided by dBFT context, it's an implementation-specific field, + // and thus, should be managed outside the dBFT library. For simulation simplicity, let's assume + // that NextConsensus is filled by every CN separately and is not verified. + block.base.NextConsensus = crypto.Uint160{1, 2, 3} block.base.PrevHash = prevHash block.base.Version = version block.base.ConsensusData = nonce diff --git a/internal/block/block_test.go b/internal/block/block_test.go index 25e27e86..96f98035 100644 --- a/internal/block/block_test.go +++ b/internal/block/block_test.go @@ -29,9 +29,6 @@ func TestNeoBlock_Setters(t *testing.T) { b.base.Version = 42 assert.EqualValues(t, 42, b.Version()) - b.base.NextConsensus = crypto.Uint160{1} - assert.Equal(t, crypto.Uint160{1}, b.NextConsensus()) - b.base.PrevHash = crypto.Uint256{3, 7} assert.Equal(t, crypto.Uint256{3, 7}, b.PrevHash()) diff --git a/internal/payload/consensus_message.go b/internal/payload/consensus_message.go index dd0e2436..f0285aa7 100644 --- a/internal/payload/consensus_message.go +++ b/internal/payload/consensus_message.go @@ -31,7 +31,7 @@ type ( } ) -var _ dbft.ConsensusMessage[crypto.Uint256, crypto.Uint160] = (*message)(nil) +var _ dbft.ConsensusMessage[crypto.Uint256] = (*message)(nil) // EncodeBinary implements Serializable interface. func (m message) EncodeBinary(w *gob.Encoder) error { @@ -81,16 +81,16 @@ func (m *message) DecodeBinary(r *gob.Decoder) error { } func (m message) GetChangeView() dbft.ChangeView { return m.payload.(dbft.ChangeView) } -func (m message) GetPrepareRequest() dbft.PrepareRequest[crypto.Uint256, crypto.Uint160] { - return m.payload.(dbft.PrepareRequest[crypto.Uint256, crypto.Uint160]) +func (m message) GetPrepareRequest() dbft.PrepareRequest[crypto.Uint256] { + return m.payload.(dbft.PrepareRequest[crypto.Uint256]) } func (m message) GetPrepareResponse() dbft.PrepareResponse[crypto.Uint256] { return m.payload.(dbft.PrepareResponse[crypto.Uint256]) } func (m message) GetCommit() dbft.Commit { return m.payload.(dbft.Commit) } func (m message) GetRecoveryRequest() dbft.RecoveryRequest { return m.payload.(dbft.RecoveryRequest) } -func (m message) GetRecoveryMessage() dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] { - return m.payload.(dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160]) +func (m message) GetRecoveryMessage() dbft.RecoveryMessage[crypto.Uint256] { + return m.payload.(dbft.RecoveryMessage[crypto.Uint256]) } // ViewNumber implements ConsensusMessage interface. diff --git a/internal/payload/constructors.go b/internal/payload/constructors.go index 68f19fe7..712b13dd 100644 --- a/internal/payload/constructors.go +++ b/internal/payload/constructors.go @@ -6,7 +6,7 @@ import ( ) // NewConsensusPayload returns minimal ConsensusPayload implementation. -func NewConsensusPayload(t dbft.MessageType, height uint32, validatorIndex uint16, viewNumber byte, consensusMessage any) dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { +func NewConsensusPayload(t dbft.MessageType, height uint32, validatorIndex uint16, viewNumber byte, consensusMessage any) dbft.ConsensusPayload[crypto.Uint256] { return &Payload{ message: message{ cmType: t, @@ -19,12 +19,11 @@ func NewConsensusPayload(t dbft.MessageType, height uint32, validatorIndex uint1 } // NewPrepareRequest returns minimal prepareRequest implementation. -func NewPrepareRequest(ts uint64, nonce uint64, nextConsensus crypto.Uint160, transactionsHashes []crypto.Uint256) dbft.PrepareRequest[crypto.Uint256, crypto.Uint160] { +func NewPrepareRequest(ts uint64, nonce uint64, transactionsHashes []crypto.Uint256) dbft.PrepareRequest[crypto.Uint256] { return &prepareRequest{ transactionHashes: transactionsHashes, nonce: nonce, timestamp: nanoSecToSec(ts), - nextConsensus: nextConsensus, } } @@ -58,7 +57,7 @@ func NewRecoveryRequest(ts uint64) dbft.RecoveryRequest { } // NewRecoveryMessage returns minimal RecoveryMessage implementation. -func NewRecoveryMessage(preparationHash *crypto.Uint256) dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] { +func NewRecoveryMessage(preparationHash *crypto.Uint256) dbft.RecoveryMessage[crypto.Uint256] { return &recoveryMessage{ preparationHash: preparationHash, preparationPayloads: make([]preparationCompact, 0), diff --git a/internal/payload/message.go b/internal/payload/message.go index a39c49a4..b11f4127 100644 --- a/internal/payload/message.go +++ b/internal/payload/message.go @@ -32,7 +32,7 @@ type ( } ) -var _ dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] = (*Payload)(nil) +var _ dbft.ConsensusPayload[crypto.Uint256] = (*Payload)(nil) // EncodeBinary implements Serializable interface. func (p Payload) EncodeBinary(w *gob.Encoder) error { diff --git a/internal/payload/message_test.go b/internal/payload/message_test.go index 59fc44a6..aa764a64 100644 --- a/internal/payload/message_test.go +++ b/internal/payload/message_test.go @@ -107,11 +107,11 @@ func TestRecoveryMessage_NoPayloads(t *testing.T) { rec := m.GetRecoveryMessage() require.NotNil(t, rec) - var p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] + var p dbft.ConsensusPayload[crypto.Uint256] require.NotPanics(t, func() { p = rec.GetPrepareRequest(p, validators, 0) }) require.Nil(t, p) - var ps []dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] + var ps []dbft.ConsensusPayload[crypto.Uint256] require.NotPanics(t, func() { ps = rec.GetPrepareResponses(p, validators) }) require.Len(t, ps, 0) diff --git a/internal/payload/prepare_request.go b/internal/payload/prepare_request.go index 1fffb097..2c67f670 100644 --- a/internal/payload/prepare_request.go +++ b/internal/payload/prepare_request.go @@ -12,18 +12,16 @@ type ( transactionHashes []crypto.Uint256 nonce uint64 timestamp uint32 - nextConsensus crypto.Uint160 } // prepareRequestAux is an auxiliary structure for prepareRequest encoding. prepareRequestAux struct { TransactionHashes []crypto.Uint256 Nonce uint64 Timestamp uint32 - NextConsensus crypto.Uint160 } ) -var _ dbft.PrepareRequest[crypto.Uint256, crypto.Uint160] = (*prepareRequest)(nil) +var _ dbft.PrepareRequest[crypto.Uint256] = (*prepareRequest)(nil) // EncodeBinary implements Serializable interface. func (p prepareRequest) EncodeBinary(w *gob.Encoder) error { @@ -31,7 +29,6 @@ func (p prepareRequest) EncodeBinary(w *gob.Encoder) error { TransactionHashes: p.transactionHashes, Nonce: p.nonce, Timestamp: p.timestamp, - NextConsensus: p.nextConsensus, }) } @@ -44,7 +41,6 @@ func (p *prepareRequest) DecodeBinary(r *gob.Decoder) error { p.timestamp = aux.Timestamp p.nonce = aux.Nonce - p.nextConsensus = aux.NextConsensus p.transactionHashes = aux.TransactionHashes return nil } @@ -63,8 +59,3 @@ func (p prepareRequest) Nonce() uint64 { func (p prepareRequest) TransactionHashes() []crypto.Uint256 { return p.transactionHashes } - -// NextConsensus implements PrepareRequest interface. -func (p prepareRequest) NextConsensus() crypto.Uint160 { - return p.nextConsensus -} diff --git a/internal/payload/recovery_message.go b/internal/payload/recovery_message.go index f98647f3..20831564 100644 --- a/internal/payload/recovery_message.go +++ b/internal/payload/recovery_message.go @@ -14,7 +14,7 @@ type ( preparationPayloads []preparationCompact commitPayloads []commitCompact changeViewPayloads []changeViewCompact - prepareRequest dbft.PrepareRequest[crypto.Uint256, crypto.Uint160] + prepareRequest dbft.PrepareRequest[crypto.Uint256] } // recoveryMessageAux is an auxiliary structure for recoveryMessage encoding. recoveryMessageAux struct { @@ -24,7 +24,7 @@ type ( } ) -var _ dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] = (*recoveryMessage)(nil) +var _ dbft.RecoveryMessage[crypto.Uint256] = (*recoveryMessage)(nil) // PreparationHash implements RecoveryMessage interface. func (m *recoveryMessage) PreparationHash() *crypto.Uint256 { @@ -32,7 +32,7 @@ func (m *recoveryMessage) PreparationHash() *crypto.Uint256 { } // AddPayload implements RecoveryMessage interface. -func (m *recoveryMessage) AddPayload(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160]) { +func (m *recoveryMessage) AddPayload(p dbft.ConsensusPayload[crypto.Uint256]) { switch p.Type() { case dbft.PrepareRequestType: m.prepareRequest = p.GetPrepareRequest() @@ -58,7 +58,7 @@ func (m *recoveryMessage) AddPayload(p dbft.ConsensusPayload[crypto.Uint256, cry } } -func fromPayload(t dbft.MessageType, recovery dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], p Serializable) *Payload { +func fromPayload(t dbft.MessageType, recovery dbft.ConsensusPayload[crypto.Uint256], p Serializable) *Payload { return &Payload{ message: message{ cmType: t, @@ -70,7 +70,7 @@ func fromPayload(t dbft.MessageType, recovery dbft.ConsensusPayload[crypto.Uint2 } // GetPrepareRequest implements RecoveryMessage interface. -func (m *recoveryMessage) GetPrepareRequest(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], _ []dbft.PublicKey, ind uint16) dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { +func (m *recoveryMessage) GetPrepareRequest(p dbft.ConsensusPayload[crypto.Uint256], _ []dbft.PublicKey, ind uint16) dbft.ConsensusPayload[crypto.Uint256] { if m.prepareRequest == nil { return nil } @@ -80,7 +80,6 @@ func (m *recoveryMessage) GetPrepareRequest(p dbft.ConsensusPayload[crypto.Uint2 timestamp: nanoSecToSec(m.prepareRequest.Timestamp()), nonce: m.prepareRequest.Nonce(), transactionHashes: m.prepareRequest.TransactionHashes(), - nextConsensus: m.prepareRequest.NextConsensus(), }) req.SetValidatorIndex(ind) @@ -88,12 +87,12 @@ func (m *recoveryMessage) GetPrepareRequest(p dbft.ConsensusPayload[crypto.Uint2 } // GetPrepareResponses implements RecoveryMessage interface. -func (m *recoveryMessage) GetPrepareResponses(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { +func (m *recoveryMessage) GetPrepareResponses(p dbft.ConsensusPayload[crypto.Uint256], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256] { if m.preparationHash == nil { return nil } - payloads := make([]dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], len(m.preparationPayloads)) + payloads := make([]dbft.ConsensusPayload[crypto.Uint256], len(m.preparationPayloads)) for i, resp := range m.preparationPayloads { payloads[i] = fromPayload(dbft.PrepareResponseType, p, &prepareResponse{ @@ -106,8 +105,8 @@ func (m *recoveryMessage) GetPrepareResponses(p dbft.ConsensusPayload[crypto.Uin } // GetChangeViews implements RecoveryMessage interface. -func (m *recoveryMessage) GetChangeViews(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { - payloads := make([]dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], len(m.changeViewPayloads)) +func (m *recoveryMessage) GetChangeViews(p dbft.ConsensusPayload[crypto.Uint256], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256] { + payloads := make([]dbft.ConsensusPayload[crypto.Uint256], len(m.changeViewPayloads)) for i, cv := range m.changeViewPayloads { payloads[i] = fromPayload(dbft.ChangeViewType, p, &changeView{ @@ -121,8 +120,8 @@ func (m *recoveryMessage) GetChangeViews(p dbft.ConsensusPayload[crypto.Uint256, } // GetCommits implements RecoveryMessage interface. -func (m *recoveryMessage) GetCommits(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { - payloads := make([]dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], len(m.commitPayloads)) +func (m *recoveryMessage) GetCommits(p dbft.ConsensusPayload[crypto.Uint256], _ []dbft.PublicKey) []dbft.ConsensusPayload[crypto.Uint256] { + payloads := make([]dbft.ConsensusPayload[crypto.Uint256], len(m.commitPayloads)) for i, c := range m.commitPayloads { payloads[i] = fromPayload(dbft.CommitType, p, &commit{signature: c.Signature}) diff --git a/internal/simulation/main.go b/internal/simulation/main.go index 8cc655db..387007f3 100644 --- a/internal/simulation/main.go +++ b/internal/simulation/main.go @@ -27,8 +27,8 @@ import ( type ( simNode struct { id int - d *dbft.DBFT[crypto.Uint256, crypto.Uint160] - messages chan dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] + d *dbft.DBFT[crypto.Uint256] + messages chan dbft.ConsensusPayload[crypto.Uint256] key dbft.PrivateKey pub dbft.PublicKey pool *memPool @@ -110,17 +110,17 @@ func initNodes(nodes []*simNode, log *zap.Logger) { } } -func newBlockFromContext(ctx *dbft.Context[crypto.Uint256, crypto.Uint160]) dbft.Block[crypto.Uint256, crypto.Uint160] { +func newBlockFromContext(ctx *dbft.Context[crypto.Uint256]) dbft.Block[crypto.Uint256] { if ctx.TransactionHashes == nil { return nil } - block := block.NewBlock(ctx.Timestamp, ctx.BlockIndex, ctx.NextConsensus, ctx.PrevHash, ctx.Version, ctx.Nonce, ctx.TransactionHashes) + block := block.NewBlock(ctx.Timestamp, ctx.BlockIndex, ctx.PrevHash, ctx.Version, ctx.Nonce, ctx.TransactionHashes) return block } // defaultNewConsensusPayload is default function for creating // consensus payload of specific type. -func defaultNewConsensusPayload(c *dbft.Context[crypto.Uint256, crypto.Uint160], t dbft.MessageType, msg any) dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160] { +func defaultNewConsensusPayload(c *dbft.Context[crypto.Uint256], t dbft.MessageType, msg any) dbft.ConsensusPayload[crypto.Uint256] { return payload.NewConsensusPayload(t, c.BlockIndex, uint16(c.MyIndex), c.ViewNumber, msg) } @@ -128,7 +128,7 @@ func initSimNode(nodes []*simNode, i int, log *zap.Logger) error { key, pub := crypto.Generate(rand.Reader) nodes[i] = &simNode{ id: i, - messages: make(chan dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160], defaultChanSize), + messages: make(chan dbft.ConsensusPayload[crypto.Uint256], defaultChanSize), key: key, pub: pub, pool: newMemoryPool(), @@ -136,31 +136,30 @@ func initSimNode(nodes []*simNode, i int, log *zap.Logger) error { cluster: nodes, } - nodes[i].d = dbft.New[crypto.Uint256, crypto.Uint160]( - dbft.WithLogger[crypto.Uint256, crypto.Uint160](nodes[i].log), - dbft.WithSecondsPerBlock[crypto.Uint256, crypto.Uint160](time.Second*5), - dbft.WithKeyPair[crypto.Uint256, crypto.Uint160](key, pub), - dbft.WithGetTx[crypto.Uint256, crypto.Uint160](nodes[i].pool.Get), - dbft.WithGetVerified[crypto.Uint256, crypto.Uint160](nodes[i].pool.GetVerified), - dbft.WithBroadcast[crypto.Uint256, crypto.Uint160](nodes[i].Broadcast), - dbft.WithProcessBlock[crypto.Uint256, crypto.Uint160](nodes[i].ProcessBlock), - dbft.WithCurrentHeight[crypto.Uint256, crypto.Uint160](nodes[i].CurrentHeight), - dbft.WithCurrentBlockHash[crypto.Uint256, crypto.Uint160](nodes[i].CurrentBlockHash), - dbft.WithGetValidators[crypto.Uint256, crypto.Uint160](nodes[i].GetValidators), - dbft.WithVerifyPrepareRequest[crypto.Uint256, crypto.Uint160](nodes[i].VerifyPayload), - dbft.WithVerifyPrepareResponse[crypto.Uint256, crypto.Uint160](nodes[i].VerifyPayload), - - dbft.WithNewBlockFromContext[crypto.Uint256, crypto.Uint160](newBlockFromContext), - dbft.WithGetConsensusAddress[crypto.Uint256, crypto.Uint160](func(...dbft.PublicKey) crypto.Uint160 { return crypto.Uint160{} }), - dbft.WithNewConsensusPayload[crypto.Uint256, crypto.Uint160](defaultNewConsensusPayload), - dbft.WithNewPrepareRequest[crypto.Uint256, crypto.Uint160](payload.NewPrepareRequest), - dbft.WithNewPrepareResponse[crypto.Uint256, crypto.Uint160](payload.NewPrepareResponse), - dbft.WithNewChangeView[crypto.Uint256, crypto.Uint160](payload.NewChangeView), - dbft.WithNewCommit[crypto.Uint256, crypto.Uint160](payload.NewCommit), - dbft.WithNewRecoveryMessage[crypto.Uint256, crypto.Uint160](func() dbft.RecoveryMessage[crypto.Uint256, crypto.Uint160] { + nodes[i].d = dbft.New[crypto.Uint256]( + dbft.WithLogger[crypto.Uint256](nodes[i].log), + dbft.WithSecondsPerBlock[crypto.Uint256](time.Second*5), + dbft.WithKeyPair[crypto.Uint256](key, pub), + dbft.WithGetTx[crypto.Uint256](nodes[i].pool.Get), + dbft.WithGetVerified[crypto.Uint256](nodes[i].pool.GetVerified), + dbft.WithBroadcast[crypto.Uint256](nodes[i].Broadcast), + dbft.WithProcessBlock[crypto.Uint256](nodes[i].ProcessBlock), + dbft.WithCurrentHeight[crypto.Uint256](nodes[i].CurrentHeight), + dbft.WithCurrentBlockHash[crypto.Uint256](nodes[i].CurrentBlockHash), + dbft.WithGetValidators[crypto.Uint256](nodes[i].GetValidators), + dbft.WithVerifyPrepareRequest[crypto.Uint256](nodes[i].VerifyPayload), + dbft.WithVerifyPrepareResponse[crypto.Uint256](nodes[i].VerifyPayload), + + dbft.WithNewBlockFromContext[crypto.Uint256](newBlockFromContext), + dbft.WithNewConsensusPayload[crypto.Uint256](defaultNewConsensusPayload), + dbft.WithNewPrepareRequest[crypto.Uint256](payload.NewPrepareRequest), + dbft.WithNewPrepareResponse[crypto.Uint256](payload.NewPrepareResponse), + dbft.WithNewChangeView[crypto.Uint256](payload.NewChangeView), + dbft.WithNewCommit[crypto.Uint256](payload.NewCommit), + dbft.WithNewRecoveryMessage[crypto.Uint256](func() dbft.RecoveryMessage[crypto.Uint256] { return payload.NewRecoveryMessage(nil) }), - dbft.WithNewRecoveryRequest[crypto.Uint256, crypto.Uint160](payload.NewRecoveryRequest), + dbft.WithNewRecoveryRequest[crypto.Uint256](payload.NewRecoveryRequest), ) if nodes[i].d == nil { @@ -193,7 +192,7 @@ func sortValidators(pubs []dbft.PublicKey) { }) } -func (n *simNode) Broadcast(m dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160]) { +func (n *simNode) Broadcast(m dbft.ConsensusPayload[crypto.Uint256]) { for i, node := range n.cluster { if i != n.id { select { @@ -213,7 +212,7 @@ func (n *simNode) GetValidators(...dbft.Transaction[crypto.Uint256]) []dbft.Publ return n.validators } -func (n *simNode) ProcessBlock(b dbft.Block[crypto.Uint256, crypto.Uint160]) { +func (n *simNode) ProcessBlock(b dbft.Block[crypto.Uint256]) { n.d.Logger.Debug("received block", zap.Uint32("height", b.Index())) for _, tx := range b.Transactions() { @@ -225,7 +224,7 @@ func (n *simNode) ProcessBlock(b dbft.Block[crypto.Uint256, crypto.Uint160]) { } // VerifyPayload verifies that payload was received from a good validator. -func (n *simNode) VerifyPayload(p dbft.ConsensusPayload[crypto.Uint256, crypto.Uint160]) error { +func (n *simNode) VerifyPayload(p dbft.ConsensusPayload[crypto.Uint256]) error { if *blocked != -1 && p.ValidatorIndex() == uint16(*blocked) { return fmt.Errorf("message from blocked validator: %d", *blocked) } diff --git a/prepare_request.go b/prepare_request.go index c27a2318..3ba594c9 100644 --- a/prepare_request.go +++ b/prepare_request.go @@ -1,14 +1,11 @@ package dbft // PrepareRequest represents dBFT PrepareRequest message. -type PrepareRequest[H Hash, A Address] interface { +type PrepareRequest[H Hash] interface { // Timestamp returns this message's timestamp. Timestamp() uint64 // Nonce is a random nonce. Nonce() uint64 // TransactionHashes returns hashes of all transaction in a proposed block. TransactionHashes() []H - // NextConsensus returns hash which is based on which validators will - // try to agree on a block in the current epoch. - NextConsensus() A } diff --git a/recovery_message.go b/recovery_message.go index 8e6f760d..303ecad0 100644 --- a/recovery_message.go +++ b/recovery_message.go @@ -1,17 +1,17 @@ package dbft // RecoveryMessage represents dBFT Recovery message. -type RecoveryMessage[H Hash, A Address] interface { +type RecoveryMessage[H Hash] interface { // AddPayload adds payload from this epoch to be recovered. - AddPayload(p ConsensusPayload[H, A]) + AddPayload(p ConsensusPayload[H]) // GetPrepareRequest returns PrepareRequest to be processed. - GetPrepareRequest(p ConsensusPayload[H, A], validators []PublicKey, primary uint16) ConsensusPayload[H, A] + GetPrepareRequest(p ConsensusPayload[H], validators []PublicKey, primary uint16) ConsensusPayload[H] // GetPrepareResponses returns a slice of PrepareResponse in any order. - GetPrepareResponses(p ConsensusPayload[H, A], validators []PublicKey) []ConsensusPayload[H, A] + GetPrepareResponses(p ConsensusPayload[H], validators []PublicKey) []ConsensusPayload[H] // GetChangeViews returns a slice of ChangeView in any order. - GetChangeViews(p ConsensusPayload[H, A], validators []PublicKey) []ConsensusPayload[H, A] + GetChangeViews(p ConsensusPayload[H], validators []PublicKey) []ConsensusPayload[H] // GetCommits returns a slice of Commit in any order. - GetCommits(p ConsensusPayload[H, A], validators []PublicKey) []ConsensusPayload[H, A] + GetCommits(p ConsensusPayload[H], validators []PublicKey) []ConsensusPayload[H] // PreparationHash returns has of PrepareRequest payload for this epoch. // It can be useful in case only PrepareResponse payloads were received. diff --git a/send.go b/send.go index 4e32149a..9ab7ac76 100644 --- a/send.go +++ b/send.go @@ -4,7 +4,7 @@ import ( "go.uber.org/zap" ) -func (d *DBFT[H, A]) broadcast(msg ConsensusPayload[H, A]) { +func (d *DBFT[H]) broadcast(msg ConsensusPayload[H]) { d.Logger.Debug("broadcasting message", zap.Stringer("type", msg.Type()), zap.Uint32("height", d.BlockIndex), @@ -14,15 +14,15 @@ func (d *DBFT[H, A]) broadcast(msg ConsensusPayload[H, A]) { d.Broadcast(msg) } -func (c *Context[H, A]) makePrepareRequest() ConsensusPayload[H, A] { +func (c *Context[H]) makePrepareRequest() ConsensusPayload[H] { c.Fill() - req := c.Config.NewPrepareRequest(c.Timestamp, c.Nonce, c.NextConsensus, c.TransactionHashes) + req := c.Config.NewPrepareRequest(c.Timestamp, c.Nonce, c.TransactionHashes) return c.Config.NewConsensusPayload(c, PrepareRequestType, req) } -func (d *DBFT[H, A]) sendPrepareRequest() { +func (d *DBFT[H]) sendPrepareRequest() { msg := d.makePrepareRequest() d.PreparationPayloads[d.MyIndex] = msg d.broadcast(msg) @@ -37,7 +37,7 @@ func (d *DBFT[H, A]) sendPrepareRequest() { d.checkPrepare() } -func (c *Context[H, A]) makeChangeView(ts uint64, reason ChangeViewReason) ConsensusPayload[H, A] { +func (c *Context[H]) makeChangeView(ts uint64, reason ChangeViewReason) ConsensusPayload[H] { cv := c.Config.NewChangeView(c.ViewNumber+1, reason, ts) msg := c.Config.NewConsensusPayload(c, ChangeViewType, cv) @@ -46,7 +46,7 @@ func (c *Context[H, A]) makeChangeView(ts uint64, reason ChangeViewReason) Conse return msg } -func (d *DBFT[H, A]) sendChangeView(reason ChangeViewReason) { +func (d *DBFT[H]) sendChangeView(reason ChangeViewReason) { if d.Context.WatchOnly() { return } @@ -83,7 +83,7 @@ func (d *DBFT[H, A]) sendChangeView(reason ChangeViewReason) { d.checkChangeView(newView) } -func (c *Context[H, A]) makePrepareResponse() ConsensusPayload[H, A] { +func (c *Context[H]) makePrepareResponse() ConsensusPayload[H] { resp := c.Config.NewPrepareResponse(c.PreparationPayloads[c.PrimaryIndex].Hash()) msg := c.Config.NewConsensusPayload(c, PrepareResponseType, resp) @@ -92,14 +92,14 @@ func (c *Context[H, A]) makePrepareResponse() ConsensusPayload[H, A] { return msg } -func (d *DBFT[H, A]) sendPrepareResponse() { +func (d *DBFT[H]) sendPrepareResponse() { msg := d.makePrepareResponse() d.Logger.Info("sending PrepareResponse", zap.Uint32("height", d.BlockIndex), zap.Uint("view", uint(d.ViewNumber))) d.StopTxFlow() d.broadcast(msg) } -func (c *Context[H, A]) makeCommit() ConsensusPayload[H, A] { +func (c *Context[H]) makeCommit() ConsensusPayload[H] { if msg := c.CommitPayloads[c.MyIndex]; msg != nil { return msg } @@ -118,14 +118,14 @@ func (c *Context[H, A]) makeCommit() ConsensusPayload[H, A] { return nil } -func (d *DBFT[H, A]) sendCommit() { +func (d *DBFT[H]) sendCommit() { msg := d.makeCommit() d.CommitPayloads[d.MyIndex] = msg d.Logger.Info("sending Commit", zap.Uint32("height", d.BlockIndex), zap.Uint("view", uint(d.ViewNumber))) d.broadcast(msg) } -func (d *DBFT[H, A]) sendRecoveryRequest() { +func (d *DBFT[H]) sendRecoveryRequest() { // If we're here, something is wrong, we either missing some messages or // transactions or both, so re-request missing transactions here too. if d.RequestSentOrReceived() && !d.hasAllTransactions() { @@ -135,7 +135,7 @@ func (d *DBFT[H, A]) sendRecoveryRequest() { d.broadcast(d.Config.NewConsensusPayload(&d.Context, RecoveryRequestType, req)) } -func (c *Context[H, A]) makeRecoveryMessage() ConsensusPayload[H, A] { +func (c *Context[H]) makeRecoveryMessage() ConsensusPayload[H] { recovery := c.Config.NewRecoveryMessage() for _, p := range c.PreparationPayloads { @@ -165,6 +165,6 @@ func (c *Context[H, A]) makeRecoveryMessage() ConsensusPayload[H, A] { return c.Config.NewConsensusPayload(c, RecoveryMessageType, recovery) } -func (d *DBFT[H, A]) sendRecoveryMessage() { +func (d *DBFT[H]) sendRecoveryMessage() { d.broadcast(d.makeRecoveryMessage()) }