Documentation ¶
Overview ¶
Package bdls implements Sperax Byzantine Fault Tolerance in Partially Connected Asynchronous Networks based on https://eprint.iacr.org/2019/1460.pdf.
To make the runtime behavior of consensus algorithm predictable, as a function: y = f(x, t), where 'x' is the message it received, and 't' is the time while being called, and 'y' is the deterministic status of consensus after 'x' and 't' applied to 'f', this library has been designed in a deterministic scheme, without parallel computing, networking, and current time is a parameter to this library.
As it's a pure algorithm implementation, it's not thread-safe! Users of this library should take care of their own sychronziation mechanism.
Index ¶
- Constants
- Variables
- func VerifyConfig(c *Config) error
- type Config
- type Consensus
- func (c *Consensus) CurrentProof() *SignedProto
- func (c *Consensus) CurrentState() (height uint64, round uint64, data State)
- func (c *Consensus) DecodeSignedMessage(bts []byte) (*SignedProto, error)
- func (c *Consensus) Join(p PeerInterface) bool
- func (c *Consensus) Leave(addr net.Addr) bool
- func (c *Consensus) Propose(s State)
- func (c *Consensus) ReceiveMessage(bts []byte, now time.Time) error
- func (c *Consensus) SetLatency(latency time.Duration)
- func (c *Consensus) Update(now time.Time) error
- func (c *Consensus) ValidateDecideMessage(bts []byte, targetState []byte) error
- type Coordinate
- type IPCPeer
- func (p *IPCPeer) Close()
- func (p *IPCPeer) GetBytesCount() int64
- func (p *IPCPeer) GetLatencies() (min time.Duration, max time.Duration, total time.Duration)
- func (p *IPCPeer) GetLatestState() (height uint64, round uint64, data State)
- func (p *IPCPeer) GetMessageCount() int64
- func (p *IPCPeer) GetPublicKey() *ecdsa.PublicKey
- func (p *IPCPeer) Propose(s State)
- func (p *IPCPeer) RemoteAddr() net.Addr
- func (p *IPCPeer) Send(msg []byte) error
- func (p *IPCPeer) Update()
- type Message
- func (*Message) Descriptor() ([]byte, []int)
- func (m *Message) GetHeight() uint64
- func (m *Message) GetLockRelease() *SignedProto
- func (m *Message) GetProof() []*SignedProto
- func (m *Message) GetRound() uint64
- func (m *Message) GetState() []byte
- func (m *Message) GetType() MessageType
- func (m *Message) Marshal() (dAtA []byte, err error)
- func (m *Message) MarshalTo(dAtA []byte) (int, error)
- func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error)
- func (*Message) ProtoMessage()
- func (m *Message) Reset()
- func (m *Message) Size() (n int)
- func (m *Message) String() string
- func (m *Message) Unmarshal(dAtA []byte) error
- func (m *Message) XXX_DiscardUnknown()
- func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (m *Message) XXX_Merge(src proto.Message)
- func (m *Message) XXX_Size() int
- func (m *Message) XXX_Unmarshal(b []byte) error
- type MessageType
- type PeerInterface
- type PubKeyAxis
- type SignedProto
- func (sp *SignedProto) Coordinate() (ret Coordinate)
- func (*SignedProto) Descriptor() ([]byte, []int)
- func (m *SignedProto) GetMessage() []byte
- func (m *SignedProto) GetR() []byte
- func (m *SignedProto) GetS() []byte
- func (m *SignedProto) GetVersion() uint32
- func (sp *SignedProto) Hash() []byte
- func (m *SignedProto) Marshal() (dAtA []byte, err error)
- func (m *SignedProto) MarshalTo(dAtA []byte) (int, error)
- func (m *SignedProto) MarshalToSizedBuffer(dAtA []byte) (int, error)
- func (*SignedProto) ProtoMessage()
- func (m *SignedProto) Reset()
- func (sp *SignedProto) Sign(m *Message, privateKey *ecdsa.PrivateKey)
- func (m *SignedProto) Size() (n int)
- func (m *SignedProto) String() string
- func (m *SignedProto) Unmarshal(dAtA []byte) error
- func (sp *SignedProto) Verify() bool
- func (m *SignedProto) XXX_DiscardUnknown()
- func (m *SignedProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (m *SignedProto) XXX_Merge(src proto.Message)
- func (m *SignedProto) XXX_Size() int
- func (m *SignedProto) XXX_Unmarshal(b []byte) error
- type State
- type StateHash
Constants ¶
const ( // ProtocolVersion is the current BDLS protocol implementation version, // version wil be sent along with messages for protocol upgrading. ProtocolVersion = 1 // DefaultConsensusLatency is the default propagation latency setting for // consensus protocol, user can adjust consensus object's latency setting // via Consensus.SetLatency() DefaultConsensusLatency = 300 * time.Millisecond )
const ( // SizeAxis defines byte size of X-axis or Y-axis in a public key SizeAxis = 32 // SignaturePrefix is the prefix for signing a consensus message SignaturePrefix = "===Sperax Signed Message===\n" )
const (
// ConfigMinimumParticipants is the minimum number of participant allow in consensus protocol
ConfigMinimumParticipants = 4
)
Variables ¶
var ( // Config Related ErrConfigEpoch = errors.New("Config.Epoch is nil") ErrConfigStateNil = errors.New("Config.CurrentState is nil") ErrConfigLess = errors.New("Config.Less function has not set") ErrConfigValidateState = errors.New("Config.ValidateState function has not set") ErrConfigPrivateKey = errors.New("Config.PrivateKey has not set") ErrConfigParticipants = errors.New("Config.Participants must contain at least 4 participants") // common errors related to every message ErrMessageVersion = errors.New("the message has different version") ErrMessageIsEmpty = errors.New("the message being verified is empty") ErrMessageUnknownMessageType = errors.New("unrecognized message type") ErrMessageSignature = errors.New("cannot verify the signature of this message") ErrMessageUnknownParticipant = errors.New("the message is from unknown partcipants") // <roundchange> related ErrRoundChangeHeightMismatch = errors.New("the <roundchange> message has another height than expected") ErrRoundChangeRoundLower = errors.New("the <roundchange> message has lower round than expected") ErrRoundChangeStateValidation = errors.New("the state data validation failed <roundchange> message") // <lock> related ErrLockEmptyState = errors.New("the state is empty in <lock> message") ErrLockStateValidation = errors.New("the state data validation failed <lock> message") ErrLockHeightMismatch = errors.New("the <lock> message has another height than expected") ErrLockRoundLower = errors.New("the <lock> message has lower round than expected") ErrLockNotSignedByLeader = errors.New("the <lock> message is not signed by leader") ErrLockProofUnknownParticipant = errors.New("the proofs in <lock> message has unknown participant") ErrLockProofTypeMismatch = errors.New("the proofs in <lock> message is not <roundchange>") ErrLockProofHeightMismatch = errors.New("the proofs in <lock> message has mismatched height") ErrLockProofRoundMismatch = errors.New("the proofs in <lock> message has mismatched round") ErrLockProofStateValidation = errors.New("the proofs in <lock> message has invalid state data") ErrLockProofInsufficient = errors.New("the <lock> message has insufficient <roundchange> proofs to the proposed state") // <select> related ErrSelectStateValidation = errors.New("the state data validation failed <select> message") ErrSelectHeightMismatch = errors.New("the <select> message has another height than expected") ErrSelectRoundLower = errors.New("the <select> message has lower round than expected") ErrSelectNotSignedByLeader = errors.New("the <select> message is not signed by leader") ErrSelectStateMismatch = errors.New("the <select> message has nil state but proof contains non-nil state") ErrSelectProofUnknownParticipant = errors.New("the proofs in <select> message has unknown participant") ErrSelectProofTypeMismatch = errors.New("the proofs in <select> message is not <roundchange>") ErrSelectProofHeightMismatch = errors.New("the proofs in <select> message has mismatched height") ErrSelectProofRoundMismatch = errors.New("the proofs in <select> message has mismatched round") ErrSelectProofStateValidation = errors.New("the proofs in <select> message has invalid state data") ErrSelectProofNotTheMaximal = errors.New("the proposed state is not the maximal one in the <select> message") ErrSelectProofInsufficient = errors.New("the <select> message has insufficient overall proofs") ErrSelectProofExceeded = errors.New("the <select> message overall state proposals exceeded maximal") // <decide> Related ErrDecideHeightLower = errors.New("the <decide> message has lower height than expected") ErrDecideEmptyState = errors.New("the state is empty in <decide> message") ErrDecideStateValidation = errors.New("the state data validation failed <decide> message") ErrDecideNotSignedByLeader = errors.New("the <decide> message is not signed by leader") ErrDecideProofUnknownParticipant = errors.New("the proofs in <decide> message has unknown participant") ErrDecideProofTypeMismatch = errors.New("the proofs in <decide> message is not <commit>") ErrDecideProofHeightMismatch = errors.New("the proofs in <decide> message has mismatched height") ErrDecideProofRoundMismatch = errors.New("the proofs in <decide> message has mismatched round") ErrDecideProofStateValidation = errors.New("the proofs in <decide> message has invalid state data") ErrDecideProofInsufficient = errors.New("the <decide> message has insufficient <commit> proofs to the proposed state") // <lock-release> related ErrLockReleaseStatus = errors.New("received <lock-release> message in non LOCK-RELEASE state") // <commit> related ErrCommitEmptyState = errors.New("the state is empty in <commit> message") ErrCommitStateMismatch = errors.New("the state in <commit> message does not match what leader has locked") ErrCommitStateValidation = errors.New("the state data validation failed <commit> message") ErrCommitStatus = errors.New("received <commit> message in non COMMIT state") ErrCommitHeightMismatch = errors.New("the <commit> messge has another height than expected") ErrCommitRoundMismatch = errors.New("the <commit> message is from another round") // <decide> verification ErrMismatchedTargetState = errors.New("the state in <decide> message does not match the provided target state") )
var ( ErrInvalidLengthMessage = fmt.Errorf("proto: negative length found during unmarshaling") ErrIntOverflowMessage = fmt.Errorf("proto: integer overflow") ErrUnexpectedEndOfGroupMessage = fmt.Errorf("proto: unexpected end of group") )
var DefaultCurve elliptic.Curve = btcec.S256()
default elliptic curve for signing
var ErrPubKey = errors.New("incorrect pubkey format")
ErrPubKey will be returned if error found while decoding message's public key
var MessageType_name = map[int32]string{
0: "Nop",
1: "RoundChange",
2: "Lock",
3: "Select",
4: "Commit",
5: "LockRelease",
6: "Decide",
}
var MessageType_value = map[string]int32{
"Nop": 0,
"RoundChange": 1,
"Lock": 2,
"Select": 3,
"Commit": 4,
"LockRelease": 5,
"Decide": 6,
}
Functions ¶
func VerifyConfig ¶
VerifyConfig verifies the integrity of this config when creating new consensus object
Types ¶
type Config ¶
type Config struct { // the starting time point for consensus Epoch time.Time // CurrentHeight CurrentHeight uint64 // CurrentState CurrentState State // PrivateKey PrivateKey *ecdsa.PrivateKey // Consensus Group Participants []*ecdsa.PublicKey // EnableCommitUnicast sets to true to enable <commit> message to be delivered via unicast // if not(by default), <commit> message will be broadcasted EnableCommitUnicast bool // StateCompare is a function from user to compare states, // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. // Usually this would be block header in blockchain, or replication log in database, // users should check fields in block header to make comparison. StateCompare func(a State, b State) int // StateValidate is a function from user to validate the integrity of // state data. StateValidate func(State) bool // StateHash is a function from user to return a hash to uniquely identify // a state. StateHash func(State) StateHash // MessageCallback will be called if not nil before a message send out MessageCallback func(m *Message, signed *SignedProto) }
Config is to config the parameters of BDLS consensus protocol
type Consensus ¶
type Consensus struct {
// contains filtered or unexported fields
}
Consensus implements a deterministic BDLS consensus protocol.
It has no internal clocking or IO, and no parallel processing. The runtime behavior is predictable and deterministic. Users should write their own timing and IO function to feed in messages and ticks to trigger timeouts.
func NewConsensus ¶
NewConsensus creates a BDLS consensus object to participant in consensus procedure, the consensus object returned is data in memory without goroutines or other non-deterministic objects, and errors will be returned if there is problem, with the given config.
func (*Consensus) CurrentProof ¶
func (c *Consensus) CurrentProof() *SignedProto
CurrentProof returns current <decide> message for current height
func (*Consensus) CurrentState ¶
CurrentState returns current state along with current height & round, It's caller's responsibility to check if ReceiveMessage() has created a new height.
func (*Consensus) DecodeSignedMessage ¶ added in v1.1.1
func (c *Consensus) DecodeSignedMessage(bts []byte) (*SignedProto, error)
DecodeSignedMessage decodes a binary representation of signed consensus message.
func (*Consensus) Join ¶ added in v1.1.0
func (c *Consensus) Join(p PeerInterface) bool
Join adds a peer to consensus for message delivery, a peer is identified by its address.
func (*Consensus) Leave ¶ added in v1.1.0
Leave removes a peer from consensus, identified by its address
func (*Consensus) Propose ¶
Propose adds a new state to unconfirmed queue to particpate in consensus at next height.
func (*Consensus) ReceiveMessage ¶
ReceiveMessage processes incoming consensus messages, and returns error if message cannot be processed for some reason.
func (*Consensus) SetLatency ¶
SetLatency sets participants expected latency for consensus core
func (*Consensus) Update ¶
Update will process timing event for the state machine, callers from outside MUST call this function periodically(like 20ms).
func (*Consensus) ValidateDecideMessage ¶ added in v1.1.0
ValidateDecideMessage validates a <decide> message for non-participants, the consensus core must be correctly initialized to validate. the targetState is to compare the target state enclosed in decide message
type Coordinate ¶
Coordinate encodes X-axis and Y-axis for a publickey in an array
func (Coordinate) Equal ¶
func (c Coordinate) Equal(x1 PubKeyAxis, y1 PubKeyAxis) bool
Equal tests if X,Y axis equals to a coordinates
type IPCPeer ¶
IPCPeer represents an in-process peer for testing, which sends messages directly via function call, message delivery latency can be customizable to emulate variety of network latency. Delay is randomized with standard normal distribution based on given parameters.
func NewIPCPeer ¶
NewIPCPeer creates IPC based peer with latency, latency is distributed with standard normal distribution.
func (*IPCPeer) GetBytesCount ¶
GetBytesCount returns messages bytes count this peer received
func (*IPCPeer) GetLatencies ¶
GetLatencies returns actual generated latency
func (*IPCPeer) GetLatestState ¶
GetLatestState returns latest state
func (*IPCPeer) GetMessageCount ¶
GetMessageCount returns messages count this peer received
func (*IPCPeer) GetPublicKey ¶
GetPublicKey returns peer's public key as identity
func (*IPCPeer) RemoteAddr ¶
RemoteAddr implements Peer.RemoteAddr, the address is p's memory address
type Message ¶
type Message struct { // Type of this message Type MessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=bdls.MessageType" json:"Type,omitempty"` // Height in consensus Height uint64 `protobuf:"varint,2,opt,name=Height,proto3" json:"Height,omitempty"` // Round in consensus Round uint64 `protobuf:"varint,3,opt,name=Round,proto3" json:"Round,omitempty"` // Proposed state (optional) State []byte `protobuf:"bytes,4,opt,name=State,proto3" json:"State,omitempty"` // Proofs related Proof []*SignedProto `protobuf:"bytes,5,rep,name=Proof,proto3" json:"Proof,omitempty"` // for lock-release, it's an embeded <lock> message LockRelease *SignedProto `protobuf:"bytes,6,opt,name=LockRelease,proto3" json:"LockRelease,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
Message defines a consensus message
func (*Message) Descriptor ¶
func (*Message) GetLockRelease ¶
func (m *Message) GetLockRelease() *SignedProto
func (*Message) GetProof ¶
func (m *Message) GetProof() []*SignedProto
func (*Message) GetType ¶
func (m *Message) GetType() MessageType
func (*Message) MarshalToSizedBuffer ¶
func (*Message) ProtoMessage ¶
func (*Message) ProtoMessage()
func (*Message) XXX_DiscardUnknown ¶
func (m *Message) XXX_DiscardUnknown()
func (*Message) XXX_Marshal ¶
func (*Message) XXX_Unmarshal ¶
type MessageType ¶
type MessageType int32
MessageType defines supported message types
const ( // No operation, for default message type, and keepalive connection MessageType_Nop MessageType = 0 // MessageRoundChange = <roundchange> message MessageType_RoundChange MessageType = 1 // MessageLock = <lock> message MessageType_Lock MessageType = 2 // MessageSelect = <select> message MessageType_Select MessageType = 3 // MessageCommit = <commit> message MessageType_Commit MessageType = 4 // MessageLockRelease = <lock-release> message MessageType_LockRelease MessageType = 5 // MessageDecide = <decide> message MessageType_Decide MessageType = 6 )
func (MessageType) EnumDescriptor ¶
func (MessageType) EnumDescriptor() ([]byte, []int)
func (MessageType) String ¶
func (x MessageType) String() string
type PeerInterface ¶
type PeerInterface interface { // GetPublicKey returns peer's public key as identity GetPublicKey() *ecdsa.PublicKey // RemoteAddr returns remote addr RemoteAddr() net.Addr // Send a msg to this peer Send(msg []byte) error }
PeerInterface is a channel for consensus to send message to the peer
type PubKeyAxis ¶
PubKeyAxis defines X-axis or Y-axis in a public key
func (PubKeyAxis) Marshal ¶
func (t PubKeyAxis) Marshal() ([]byte, error)
Marshal implements protobuf MarshalTo
func (*PubKeyAxis) MarshalTo ¶
func (t *PubKeyAxis) MarshalTo(data []byte) (n int, err error)
MarshalTo implements protobuf MarshalTo
func (*PubKeyAxis) Unmarshal ¶
func (t *PubKeyAxis) Unmarshal(data []byte) error
Unmarshal implements protobuf Unmarshal
type SignedProto ¶
type SignedProto struct { Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` // the Message encoded raw protobuf in bytes Message []byte `protobuf:"bytes,2,opt,name=Message,proto3" json:"Message,omitempty"` // signer's public key X PubKeyAxis `protobuf:"bytes,3,opt,name=x,proto3,customtype=PubKeyAxis" json:"x"` Y PubKeyAxis `protobuf:"bytes,4,opt,name=y,proto3,customtype=PubKeyAxis" json:"y"` // signature r,s for prefix+messages+version+x+y above R []byte `protobuf:"bytes,5,opt,name=r,proto3" json:"r,omitempty"` S []byte `protobuf:"bytes,6,opt,name=s,proto3" json:"s,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
SignedProto defines a message with signature and it's publickey
func (*SignedProto) Coordinate ¶
func (sp *SignedProto) Coordinate() (ret Coordinate)
Coordinate encodes X,Y into a coordinate
func (*SignedProto) Descriptor ¶
func (*SignedProto) Descriptor() ([]byte, []int)
func (*SignedProto) GetMessage ¶
func (m *SignedProto) GetMessage() []byte
func (*SignedProto) GetR ¶
func (m *SignedProto) GetR() []byte
func (*SignedProto) GetS ¶
func (m *SignedProto) GetS() []byte
func (*SignedProto) GetVersion ¶
func (m *SignedProto) GetVersion() uint32
func (*SignedProto) Hash ¶
func (sp *SignedProto) Hash() []byte
Hash concats and hash as follows: blake2b(signPrefix + version + pubkey.X + pubkey.Y+len_32bit(msg) + message)
func (*SignedProto) Marshal ¶
func (m *SignedProto) Marshal() (dAtA []byte, err error)
func (*SignedProto) MarshalToSizedBuffer ¶
func (m *SignedProto) MarshalToSizedBuffer(dAtA []byte) (int, error)
func (*SignedProto) ProtoMessage ¶
func (*SignedProto) ProtoMessage()
func (*SignedProto) Reset ¶
func (m *SignedProto) Reset()
func (*SignedProto) Sign ¶
func (sp *SignedProto) Sign(m *Message, privateKey *ecdsa.PrivateKey)
Sign the message with a private key
func (*SignedProto) Size ¶
func (m *SignedProto) Size() (n int)
func (*SignedProto) String ¶
func (m *SignedProto) String() string
func (*SignedProto) Unmarshal ¶
func (m *SignedProto) Unmarshal(dAtA []byte) error
func (*SignedProto) Verify ¶
func (sp *SignedProto) Verify() bool
Verify the signature of this signed message
func (*SignedProto) XXX_DiscardUnknown ¶
func (m *SignedProto) XXX_DiscardUnknown()
func (*SignedProto) XXX_Marshal ¶
func (m *SignedProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
func (*SignedProto) XXX_Merge ¶
func (m *SignedProto) XXX_Merge(src proto.Message)
func (*SignedProto) XXX_Size ¶
func (m *SignedProto) XXX_Size() int
func (*SignedProto) XXX_Unmarshal ¶
func (m *SignedProto) XXX_Unmarshal(b []byte) error
type StateHash ¶
StateHash is a fixed size hash to identify a state
func DefaultHash ¶
DefaultHash is the system default hash function, if a hash function has not specified in config, this one will be used to hash and uniquely identifies a state.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package agent-tcp implements a TCP based agent to participate in consensus Challenge-Response scheme has been adopted to do interactive authentication
|
Package agent-tcp implements a TCP based agent to participate in consensus Challenge-Response scheme has been adopted to do interactive authentication |
cmd
|
|
crypto
|
|
blake2b
Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 and the extendable output function (XOF) BLAKE2Xb.
|
Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 and the extendable output function (XOF) BLAKE2Xb. |
btcec
Package btcec implements support for the elliptic curves needed for bitcoin.
|
Package btcec implements support for the elliptic curves needed for bitcoin. |