diff --git a/consensus/consensus.go b/consensus/consensus.go index 14a6a2f1e..f6fb2582e 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -29,8 +29,8 @@ import ( type Consensus struct { state State // Commits collected from validators. A map from node Id to its commitment - commitments *map[uint16]kyber.Point - finalCommitments *map[uint16]kyber.Point + commitments *map[uint32]kyber.Point + finalCommitments *map[uint32]kyber.Point aggregatedCommitment kyber.Point aggregatedFinalCommitment kyber.Point bitmap *crypto.Mask @@ -41,8 +41,8 @@ type Consensus struct { finalChallenge [32]byte // Responses collected from validators - responses *map[uint16]kyber.Scalar - finalResponses *map[uint16]kyber.Scalar + responses *map[uint32]kyber.Scalar + finalResponses *map[uint32]kyber.Scalar // map of nodeID to validator Peer object // FIXME: should use PubKey of p2p.Peer as the hashkey // However, we have assumed uint16 in consensus/consensus_leader.go:136 @@ -66,7 +66,7 @@ type Consensus struct { // Whether I am leader. False means I am validator IsLeader bool // Leader or validator Id - 2 byte - nodeID uint16 + nodeID uint32 // Consensus Id (View Id) - 4 byte consensusID uint32 // Blockhash - 32 byte @@ -132,10 +132,10 @@ func New(host host.Host, ShardID string, peers []p2p.Peer, leader p2p.Peer) *Con consensus.IsLeader = false } - consensus.commitments = &map[uint16]kyber.Point{} - consensus.finalCommitments = &map[uint16]kyber.Point{} - consensus.responses = &map[uint16]kyber.Scalar{} - consensus.finalResponses = &map[uint16]kyber.Scalar{} + consensus.commitments = &map[uint32]kyber.Point{} + consensus.finalCommitments = &map[uint32]kyber.Point{} + consensus.responses = &map[uint32]kyber.Scalar{} + consensus.finalResponses = &map[uint32]kyber.Scalar{} consensus.leader = leader for _, peer := range peers { @@ -225,10 +225,10 @@ func (consensus *Consensus) GetValidatorPeers() []p2p.Peer { // ResetState resets the state of the consensus func (consensus *Consensus) ResetState() { consensus.state = Finished - consensus.commitments = &map[uint16]kyber.Point{} - consensus.finalCommitments = &map[uint16]kyber.Point{} - consensus.responses = &map[uint16]kyber.Scalar{} - consensus.finalResponses = &map[uint16]kyber.Scalar{} + consensus.commitments = &map[uint32]kyber.Point{} + consensus.finalCommitments = &map[uint32]kyber.Point{} + consensus.responses = &map[uint32]kyber.Scalar{} + consensus.finalResponses = &map[uint32]kyber.Scalar{} mask, _ := crypto.NewMask(crypto.Ed25519Curve, consensus.PublicKeys, consensus.leader.PubKey) finalMask, _ := crypto.NewMask(crypto.Ed25519Curve, consensus.PublicKeys, consensus.leader.PubKey) @@ -474,7 +474,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header } // GetNodeID returns the nodeID -func (consensus *Consensus) GetNodeID() uint16 { +func (consensus *Consensus) GetNodeID() uint32 { return consensus.nodeID } diff --git a/consensus/consensus_leader.go b/consensus/consensus_leader.go index d5ee6f4b6..da1ce802f 100644 --- a/consensus/consensus_leader.go +++ b/consensus/consensus_leader.go @@ -2,7 +2,6 @@ package consensus import ( "bytes" - "encoding/binary" "encoding/hex" "errors" "github.com/ethereum/go-ethereum/rlp" @@ -13,6 +12,7 @@ import ( "github.com/harmony-one/harmony/p2p/host" "github.com/harmony-one/harmony/services/explorer" + consensus2 "github.com/harmony-one/harmony/consensus/proto" "github.com/harmony-one/harmony/profiler" "github.com/dedis/kyber" @@ -126,31 +126,14 @@ func (consensus *Consensus) commitByLeader(firstRound bool) { // processCommitMessage processes the commit message sent from validators func (consensus *Consensus) processCommitMessage(payload []byte, targetState State) { - if len(payload) < 4+32+2+32+64 { - consensus.Log.Debug("Received malformed message %x", payload) - return - } - // Read payload data - offset := 0 - // 4 byte consensus id - consensusID := binary.BigEndian.Uint32(payload[offset : offset+4]) - offset += 4 - - // 32 byte block hash - blockHash := payload[offset : offset+32] - offset += 32 - - // 2 byte validator id - validatorID := binary.BigEndian.Uint16(payload[offset : offset+2]) - offset += 2 + message := consensus2.Message{} + message.XXX_Unmarshal(payload) - // 32 byte commit - commitment := payload[offset : offset+32] - offset += 32 - - // 64 byte of signature on all above data - signature := payload[offset : offset+64] - offset += 64 + consensusID := message.ConsensusId + blockHash := message.BlockHash + validatorID := message.SenderId + commitment := message.Payload + signature := message.Signature // Verify signature v, ok := consensus.validators.Load(validatorID) @@ -164,7 +147,12 @@ func (consensus *Consensus) processCommitMessage(payload []byte, targetState Sta return } - if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, payload[:offset-64], signature) != nil { + message.Signature = nil + messageBytes, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Warn("Failed to marshal the announce message", "error", err) + } + if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, messageBytes, signature) != nil { consensus.Log.Warn("Received message with invalid signature", "validatorKey", consensus.leader.PubKey, "consensus", consensus) return } @@ -262,32 +250,14 @@ func (consensus *Consensus) responseByLeader(challenge kyber.Scalar, firstRound // Processes the response message sent from validators func (consensus *Consensus) processResponseMessage(payload []byte, targetState State) { - if len(payload) < 4+32+2+32+64 { - consensus.Log.Debug("Received malformed message %x", payload) - return - } - //#### Read payload data - offset := 0 - // 4 byte consensus id - consensusID := binary.BigEndian.Uint32(payload[offset : offset+4]) - offset += 4 - - // 32 byte block hash - blockHash := payload[offset : offset+32] - offset += 32 - - // 2 byte validator id - validatorID := binary.BigEndian.Uint16(payload[offset : offset+2]) - offset += 2 - - // 32 byte response - response := payload[offset : offset+32] - offset += 32 + message := consensus2.Message{} + message.XXX_Unmarshal(payload) - // 64 byte of signature on previous data - signature := payload[offset : offset+64] - offset += 64 - //#### END: Read payload data + consensusID := message.ConsensusId + blockHash := message.BlockHash + validatorID := message.SenderId + response := message.Payload + signature := message.Signature shouldProcess := true consensus.mutex.Lock() @@ -315,8 +285,12 @@ func (consensus *Consensus) processResponseMessage(payload []byte, targetState S consensus.Log.Warn("Invalid validator", "validatorID", validatorID, "consensus", consensus) return } - - if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, payload[:offset-64], signature) != nil { + message.Signature = nil + messageBytes, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Warn("Failed to marshal the announce message", "error", err) + } + if schnorr.Verify(crypto.Ed25519Curve, value.PubKey, messageBytes, signature) != nil { consensus.Log.Warn("Received message with invalid signature", "validatorKey", consensus.leader.PubKey, "consensus", consensus) return } @@ -435,7 +409,7 @@ func (consensus *Consensus) processResponseMessage(payload []byte, targetState S } } -func (consensus *Consensus) verifyResponse(commitments *map[uint16]kyber.Point, response kyber.Scalar, validatorID uint16) error { +func (consensus *Consensus) verifyResponse(commitments *map[uint32]kyber.Point, response kyber.Scalar, validatorID uint32) error { if response.Equal(crypto.Ed25519Curve.Scalar()) { return errors.New("response is zero valued") } diff --git a/consensus/consensus_leader_msg.go b/consensus/consensus_leader_msg.go index 145e44907..e654af426 100644 --- a/consensus/consensus_leader_msg.go +++ b/consensus/consensus_leader_msg.go @@ -2,9 +2,8 @@ package consensus import ( "bytes" - "encoding/binary" - "github.com/dedis/kyber" + consensus2 "github.com/harmony-one/harmony/consensus/proto" "github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/log" proto_consensus "github.com/harmony-one/harmony/proto/consensus" @@ -12,49 +11,51 @@ import ( // Constructs the announce message func (consensus *Consensus) constructAnnounceMessage() []byte { - buffer := bytes.NewBuffer([]byte{}) + message := consensus2.Message{} // 4 byte consensus id - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, consensus.consensusID) - buffer.Write(fourBytes) + message.ConsensusId = consensus.consensusID // 32 byte block hash - buffer.Write(consensus.blockHash[:]) + message.BlockHash = consensus.blockHash[:] - // 2 byte leader id - twoBytes := make([]byte, 2) - binary.BigEndian.PutUint16(twoBytes, consensus.nodeID) - buffer.Write(twoBytes) + // 4 byte sender id + message.SenderId = uint32(consensus.nodeID) // n byte of block header - // TODO(rj,minhdoan): Better to write the size of blockHeader - buffer.Write(consensus.blockHeader) + message.Payload = consensus.blockHeader + marshaledMessage, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } // 64 byte of signature on previous data - signature := consensus.signMessage(buffer.Bytes()) - buffer.Write(signature) + signature := consensus.signMessage(marshaledMessage) + message.Signature = signature + marshaledMessage, err = message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } consensus.Log.Info("New Announce", "NodeID", consensus.nodeID, "bitmap", consensus.bitmap) - return proto_consensus.ConstructConsensusMessage(proto_consensus.Announce, buffer.Bytes()) + return proto_consensus.ConstructConsensusMessage(proto_consensus.Announce, marshaledMessage) } // Construct the challenge message, returning challenge message in bytes, challenge scalar and aggregated commmitment point. func (consensus *Consensus) constructChallengeMessage(msgTypeToSend proto_consensus.MessageType) ([]byte, kyber.Scalar, kyber.Point) { - buffer := bytes.NewBuffer([]byte{}) + message := consensus2.Message{} // 4 byte consensus id - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, consensus.consensusID) - buffer.Write(fourBytes) + message.ConsensusId = consensus.consensusID // 32 byte block hash - buffer.Write(consensus.blockHash[:]) + message.BlockHash = consensus.blockHash[:] + + // 4 byte sender id + message.SenderId = uint32(consensus.nodeID) - // 2 byte leader id - twoBytes := make([]byte, 2) - binary.BigEndian.PutUint16(twoBytes, consensus.nodeID) - buffer.Write(twoBytes) + //// Payload + buffer := bytes.NewBuffer([]byte{}) commitmentsMap := consensus.commitments // msgType == Challenge bitmap := consensus.bitmap @@ -75,37 +76,47 @@ func (consensus *Consensus) constructChallengeMessage(msgTypeToSend proto_consen buffer.Write(getAggregatedKey(bitmap)) // 32 byte challenge - challengeScalar := getChallenge(aggCommitment, bitmap.AggregatePublic, buffer.Bytes()[:36]) + challengeScalar := getChallenge(aggCommitment, bitmap.AggregatePublic, message.BlockHash) bytes, err := challengeScalar.MarshalBinary() if err != nil { log.Error("Failed to serialize challenge") } buffer.Write(bytes) + message.Payload = buffer.Bytes() + //// END Payload + + marshaledMessage, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Challenge message", "error", err) + } // 64 byte of signature on previous data - signature := consensus.signMessage(buffer.Bytes()) - buffer.Write(signature) + signature := consensus.signMessage(marshaledMessage) + message.Signature = signature + marshaledMessage, err = message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Challenge message", "error", err) + } consensus.Log.Info("New Challenge", "NodeID", consensus.nodeID, "bitmap", consensus.bitmap) - return proto_consensus.ConstructConsensusMessage(msgTypeToSend, buffer.Bytes()), challengeScalar, aggCommitment + return proto_consensus.ConstructConsensusMessage(msgTypeToSend, marshaledMessage), challengeScalar, aggCommitment } // Construct the collective signature message func (consensus *Consensus) constructCollectiveSigMessage(collectiveSig [64]byte, bitmap []byte) []byte { - buffer := bytes.NewBuffer([]byte{}) + message := consensus2.Message{} // 4 byte consensus id - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, consensus.consensusID) - buffer.Write(fourBytes) + message.ConsensusId = consensus.consensusID // 32 byte block hash - buffer.Write(consensus.blockHash[:]) + message.BlockHash = consensus.blockHash[:] + + // 4 byte sender id + message.SenderId = uint32(consensus.nodeID) - // 2 byte leader id - twoBytes := make([]byte, 2) - binary.BigEndian.PutUint16(twoBytes, consensus.nodeID) - buffer.Write(twoBytes) + //// Payload + buffer := bytes.NewBuffer([]byte{}) // 64 byte collective signature buffer.Write(collectiveSig[:]) @@ -113,12 +124,23 @@ func (consensus *Consensus) constructCollectiveSigMessage(collectiveSig [64]byte // N byte bitmap buffer.Write(bitmap) + message.Payload = buffer.Bytes() + //// END Payload + + marshaledMessage, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Challenge message", "error", err) + } // 64 byte of signature on previous data - signature := consensus.signMessage(buffer.Bytes()) - buffer.Write(signature) + signature := consensus.signMessage(marshaledMessage) + message.Signature = signature + marshaledMessage, err = message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Challenge message", "error", err) + } consensus.Log.Info("New CollectiveSig", "NodeID", consensus.nodeID, "bitmap", consensus.bitmap) - return proto_consensus.ConstructConsensusMessage(proto_consensus.CollectiveSig, buffer.Bytes()) + return proto_consensus.ConstructConsensusMessage(proto_consensus.CollectiveSig, marshaledMessage) } func getAggregatedCommit(commitments []kyber.Point) (commitment kyber.Point, bytes []byte) { diff --git a/consensus/consensus_validator.go b/consensus/consensus_validator.go index 0c3f4b3d2..2c9318420 100644 --- a/consensus/consensus_validator.go +++ b/consensus/consensus_validator.go @@ -2,10 +2,10 @@ package consensus import ( "bytes" - "encoding/binary" "github.com/dedis/kyber/sign/schnorr" "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/harmony/attack" + consensus2 "github.com/harmony-one/harmony/consensus/proto" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/log" @@ -42,29 +42,15 @@ func (consensus *Consensus) ProcessMessageValidator(message []byte) { // Processes the announce message sent from the leader func (consensus *Consensus) processAnnounceMessage(payload []byte) { consensus.Log.Info("Received Announce Message", "Size", len(payload), "nodeID", consensus.nodeID) - //#### Read payload data - offset := 0 - // 4 byte consensus id - consensusID := binary.BigEndian.Uint32(payload[offset : offset+4]) - offset += 4 - // 32 byte block hash - blockHash := payload[offset : offset+32] - offset += 32 + message := consensus2.Message{} + message.XXX_Unmarshal(payload) - // 2 byte leader id - leaderID := binary.BigEndian.Uint16(payload[offset : offset+2]) - offset += 2 - - // n byte of message to cosign - n := len(payload) - offset - 64 // the number means 64 signature - blockHeader := payload[offset : offset+n] - offset += n - - // 64 byte of signature on previous data - signature := payload[offset : offset+64] - offset += 64 - //#### END: Read payload data + consensusID := message.ConsensusId + blockHash := message.BlockHash + leaderID := message.SenderId + blockHeader := message.Payload + signature := message.Signature copy(consensus.blockHash[:], blockHash[:]) @@ -77,14 +63,19 @@ func (consensus *Consensus) processAnnounceMessage(payload []byte) { } // Verify signature - if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, payload[:offset-64], signature) != nil { + message.Signature = nil + messageBytes, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Warn("Failed to marshal the announce message", "error", err) + } + if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil { consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus) return } // check block header is valid var blockHeaderObj types.Block // TODO: separate header from block. Right now, this blockHeader data is actually the whole block - err := rlp.DecodeBytes(blockHeader, &blockHeaderObj) + err = rlp.DecodeBytes(blockHeader, &blockHeaderObj) if err != nil { consensus.Log.Warn("Unparseable block header data", "error", err) return @@ -126,54 +117,48 @@ func (consensus *Consensus) processAnnounceMessage(payload []byte) { // Processes the challenge message sent from the leader func (consensus *Consensus) processChallengeMessage(payload []byte, targetState State) { - if len(payload) < 4+32+2+33+33+32+64 { - consensus.Log.Debug("Received malformed message %x", payload) - return - } - //#### Read payload data - offset := 0 - // 4 byte consensus id - consensusID := binary.BigEndian.Uint32(payload[offset : offset+4]) - offset += 4 - - // 32 byte block hash - blockHash := payload[offset : offset+32] - offset += 32 + consensus.Log.Info("Received Challenge Message", "Size", len(payload), "nodeID", consensus.nodeID) + message := consensus2.Message{} + message.XXX_Unmarshal(payload) - // 2 byte leader id - leaderID := binary.BigEndian.Uint16(payload[offset : offset+2]) - offset += 2 + consensusID := message.ConsensusId + blockHash := message.BlockHash + leaderID := message.SenderId + messagePayload := message.Payload + signature := message.Signature + //#### Read payload data + offset := 0 // 33 byte of aggregated commit - aggreCommit := payload[offset : offset+33] + aggreCommit := messagePayload[offset : offset+33] offset += 33 // 33 byte of aggregated key - aggreKey := payload[offset : offset+33] + aggreKey := messagePayload[offset : offset+33] offset += 33 // 32 byte of challenge - challenge := payload[offset : offset+32] + challenge := messagePayload[offset : offset+32] offset += 32 - // 64 byte of signature on previous data - signature := payload[offset : offset+64] - offset += 64 - //#### END: Read payload data - // Update readyByConsensus for attack. attack.GetInstance().UpdateConsensusReady(consensusID) // Verify block data and the aggregated signatures // check leader Id myLeaderID := utils.GetUniqueIDFromPeer(consensus.leader) - if leaderID != myLeaderID { + if uint32(leaderID) != myLeaderID { consensus.Log.Warn("Received message from wrong leader", "myLeaderID", myLeaderID, "receivedLeaderId", leaderID, "consensus", consensus) return } // Verify signature - if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, payload[:offset-64], signature) != nil { + message.Signature = nil + messageBytes, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Warn("Failed to marshal the announce message", "error", err) + } + if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil { consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus) return } @@ -198,7 +183,7 @@ func (consensus *Consensus) processChallengeMessage(payload []byte, targetState aggKey := crypto.Ed25519Curve.Point() aggKey.UnmarshalBinary(aggreKey[:32]) - reconstructedChallenge, err := crypto.Challenge(crypto.Ed25519Curve, aggCommitment, aggKey, payload[:36]) // Only consensus Id and block hash + reconstructedChallenge, err := crypto.Challenge(crypto.Ed25519Curve, aggCommitment, aggKey, blockHash) if err != nil { log.Error("Failed to reconstruct the challenge from commits and keys") @@ -278,56 +263,41 @@ func (consensus *Consensus) processChallengeMessage(payload []byte, targetState // Processes the collective signature message sent from the leader func (consensus *Consensus) processCollectiveSigMessage(payload []byte) { - if len(payload) < 4+32+2+64+64 { - consensus.Log.Debug("Received malformed message %x", payload) - return - } - //#### Read payload data - offset := 0 - // 4 byte consensus id - consensusID := binary.BigEndian.Uint32(payload[offset : offset+4]) - offset += 4 - - // 32 byte block hash - blockHash := payload[offset : offset+32] - offset += 32 + message := consensus2.Message{} + message.XXX_Unmarshal(payload) - // 2 byte leader id - leaderID := binary.BigEndian.Uint16(payload[offset : offset+2]) - offset += 2 + consensusID := message.ConsensusId + blockHash := message.BlockHash + leaderID := message.SenderId + messagePayload := message.Payload + signature := message.Signature - // 64 byte of collective signature - collectiveSig := payload[offset : offset+64] - offset += 64 - - // N byte of bitmap - n := len(payload) - offset - 64 // the number means 64 signature - bitmap := payload[offset : offset+n] - offset += n - - // 64 byte of signature on previous data - signature := payload[offset : offset+64] - offset += 64 + //#### Read payload data + collectiveSig := messagePayload[0:64] + bitmap := messagePayload[64:] //#### END: Read payload data - copy(consensus.blockHash[:], blockHash[:]) - // Verify block data // check leader Id myLeaderID := utils.GetUniqueIDFromPeer(consensus.leader) - if leaderID != myLeaderID { + if uint32(leaderID) != myLeaderID { consensus.Log.Warn("Received message from wrong leader", "myLeaderID", myLeaderID, "receivedLeaderId", leaderID, "consensus", consensus) return } // Verify signature - if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, payload[:offset-64], signature) != nil { + message.Signature = nil + messageBytes, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Warn("Failed to marshal the announce message", "error", err) + } + if schnorr.Verify(crypto.Ed25519Curve, consensus.leader.PubKey, messageBytes, signature) != nil { consensus.Log.Warn("Received message with invalid signature", "leaderKey", consensus.leader.PubKey, "consensus", consensus) return } // Verify collective signature - err := crypto.Verify(crypto.Ed25519Curve, consensus.PublicKeys, payload[:36], append(collectiveSig, bitmap...), crypto.NewThresholdPolicy((2*len(consensus.PublicKeys)/3)+1)) + err = crypto.Verify(crypto.Ed25519Curve, consensus.PublicKeys, blockHash, append(collectiveSig, bitmap...), crypto.NewThresholdPolicy((2*len(consensus.PublicKeys)/3)+1)) if err != nil { consensus.Log.Warn("Failed to verify the collective sig message", "consensusID", consensusID, "err", err, "bitmap", bitmap, "NodeID", consensus.nodeID, "#PK", len(consensus.PublicKeys)) return diff --git a/consensus/consensus_validator_msg.go b/consensus/consensus_validator_msg.go index b11c6eaa0..8ad0ffd57 100644 --- a/consensus/consensus_validator_msg.go +++ b/consensus/consensus_validator_msg.go @@ -1,65 +1,79 @@ package consensus import ( - "bytes" - "encoding/binary" - "github.com/dedis/kyber" + consensus2 "github.com/harmony-one/harmony/consensus/proto" "github.com/harmony-one/harmony/crypto" proto_consensus "github.com/harmony-one/harmony/proto/consensus" ) // Construct the commit message to send to leader (assumption the consensus data is already verified) func (consensus *Consensus) constructCommitMessage(msgType proto_consensus.MessageType) (secret kyber.Scalar, commitMsg []byte) { - buffer := bytes.NewBuffer([]byte{}) + message := consensus2.Message{} // 4 byte consensus id - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, consensus.consensusID) - buffer.Write(fourBytes) + message.ConsensusId = consensus.consensusID // 32 byte block hash - buffer.Write(consensus.blockHash[:]) + message.BlockHash = consensus.blockHash[:] - // 2 byte validator id - twoBytes := make([]byte, 2) - binary.BigEndian.PutUint16(twoBytes, consensus.nodeID) - buffer.Write(twoBytes) + // 4 byte sender id + message.SenderId = uint32(consensus.nodeID) // 32 byte of commit (TODO: figure out why it's different than Zilliqa's ECPoint which takes 33 bytes: https://crypto.stackexchange.com/questions/51703/how-to-convert-from-curve25519-33-byte-to-32-byte-representation) secret, commitment := crypto.Commit(crypto.Ed25519Curve) - commitment.MarshalTo(buffer) - + bytes, err := commitment.MarshalBinary() + if err != nil { + consensus.Log.Debug("Failed to marshal commit", "error", err) + } + message.Payload = bytes + + marshaledMessage, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } // 64 byte of signature on previous data - signature := consensus.signMessage(buffer.Bytes()) - buffer.Write(signature) + signature := consensus.signMessage(marshaledMessage) + message.Signature = signature - return secret, proto_consensus.ConstructConsensusMessage(msgType, buffer.Bytes()) + marshaledMessage, err = message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } + + return secret, proto_consensus.ConstructConsensusMessage(msgType, marshaledMessage) } // Construct the response message to send to leader (assumption the consensus data is already verified) func (consensus *Consensus) constructResponseMessage(msgType proto_consensus.MessageType, response kyber.Scalar) []byte { - buffer := bytes.NewBuffer([]byte{}) + message := consensus2.Message{} // 4 byte consensus id - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, consensus.consensusID) - buffer.Write(fourBytes) + message.ConsensusId = consensus.consensusID // 32 byte block hash - buffer.Write(consensus.blockHash[:32]) + message.BlockHash = consensus.blockHash[:] - // 2 byte validator id - twoBytes := make([]byte, 2) - binary.BigEndian.PutUint16(twoBytes, consensus.nodeID) - buffer.Write(twoBytes) + // 4 byte sender id + message.SenderId = uint32(consensus.nodeID) - // 32 byte of response - response.MarshalTo(buffer) + bytes, err := response.MarshalBinary() + if err != nil { + consensus.Log.Debug("Failed to marshal response", "error", err) + } + message.Payload = bytes + marshaledMessage, err := message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } // 64 byte of signature on previous data - signature := consensus.signMessage(buffer.Bytes()) - buffer.Write(signature) - - return proto_consensus.ConstructConsensusMessage(msgType, buffer.Bytes()) + signature := consensus.signMessage(marshaledMessage) + message.Signature = signature + + marshaledMessage, err = message.XXX_Marshal([]byte{}, true) + if err != nil { + consensus.Log.Debug("Failed to marshal Announce message", "error", err) + } + return proto_consensus.ConstructConsensusMessage(msgType, marshaledMessage) } diff --git a/consensus/proto/consensus.pb.go b/consensus/proto/consensus.pb.go new file mode 100644 index 000000000..4bd07b5d7 --- /dev/null +++ b/consensus/proto/consensus.pb.go @@ -0,0 +1,176 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: consensus.proto + +package consensus + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type MessageType int32 + +const ( + MessageType_UNKNOWN MessageType = 0 + MessageType_ANNOUNCE MessageType = 1 + MessageType_COMMIT MessageType = 2 + MessageType_CHALLENGE MessageType = 3 + MessageType_RESPONSE MessageType = 4 + MessageType_COLLECTIVE_SIG MessageType = 5 + MessageType_FINAL_COMMIT MessageType = 6 + MessageType_FINAL_CHALLENGE MessageType = 7 + MessageType_FINAL_RESPONSE MessageType = 8 +) + +var MessageType_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ANNOUNCE", + 2: "COMMIT", + 3: "CHALLENGE", + 4: "RESPONSE", + 5: "COLLECTIVE_SIG", + 6: "FINAL_COMMIT", + 7: "FINAL_CHALLENGE", + 8: "FINAL_RESPONSE", +} + +var MessageType_value = map[string]int32{ + "UNKNOWN": 0, + "ANNOUNCE": 1, + "COMMIT": 2, + "CHALLENGE": 3, + "RESPONSE": 4, + "COLLECTIVE_SIG": 5, + "FINAL_COMMIT": 6, + "FINAL_CHALLENGE": 7, + "FINAL_RESPONSE": 8, +} + +func (x MessageType) String() string { + return proto.EnumName(MessageType_name, int32(x)) +} + +func (MessageType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_56f0f2c53b3de771, []int{0} +} + +type Message struct { + Type MessageType `protobuf:"varint,1,opt,name=type,proto3,enum=consensus.MessageType" json:"type,omitempty"` + ConsensusId uint32 `protobuf:"varint,2,opt,name=consensus_id,json=consensusId,proto3" json:"consensus_id,omitempty"` + SenderId uint32 `protobuf:"varint,3,opt,name=sender_id,json=senderId,proto3" json:"sender_id,omitempty"` + BlockHash []byte `protobuf:"bytes,4,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"` + Signature []byte `protobuf:"bytes,6,opt,name=signature,proto3" json:"signature,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_56f0f2c53b3de771, []int{0} +} + +func (m *Message) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Message.Unmarshal(m, b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) +} +func (m *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(m, src) +} +func (m *Message) XXX_Size() int { + return xxx_messageInfo_Message.Size(m) +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +func (m *Message) GetType() MessageType { + if m != nil { + return m.Type + } + return MessageType_UNKNOWN +} + +func (m *Message) GetConsensusId() uint32 { + if m != nil { + return m.ConsensusId + } + return 0 +} + +func (m *Message) GetSenderId() uint32 { + if m != nil { + return m.SenderId + } + return 0 +} + +func (m *Message) GetBlockHash() []byte { + if m != nil { + return m.BlockHash + } + return nil +} + +func (m *Message) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +func (m *Message) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func init() { + proto.RegisterEnum("consensus.MessageType", MessageType_name, MessageType_value) + proto.RegisterType((*Message)(nil), "consensus.Message") +} + +func init() { proto.RegisterFile("consensus.proto", fileDescriptor_56f0f2c53b3de771) } + +var fileDescriptor_56f0f2c53b3de771 = []byte{ + // 302 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x91, 0xdf, 0x4e, 0xc2, 0x30, + 0x14, 0xc6, 0x2d, 0x7f, 0x36, 0x76, 0x18, 0xd0, 0x1c, 0x13, 0xd3, 0x44, 0x4d, 0xd0, 0x2b, 0xc2, + 0x05, 0x17, 0xfa, 0x04, 0x64, 0xa9, 0xd0, 0x38, 0x3a, 0x33, 0x40, 0x2f, 0x97, 0xc2, 0x1a, 0x20, + 0x92, 0x6d, 0xa1, 0x70, 0xc1, 0xdb, 0xf8, 0x40, 0x3e, 0x94, 0x61, 0x60, 0xf5, 0xb2, 0xbf, 0xdf, + 0xf7, 0x7d, 0x69, 0x72, 0xa0, 0xb3, 0xcc, 0x33, 0xa3, 0x33, 0x73, 0x30, 0x83, 0x62, 0x97, 0xef, + 0x73, 0xf4, 0x2c, 0x78, 0xfc, 0x26, 0xe0, 0x4e, 0xb4, 0x31, 0x6a, 0xa5, 0xb1, 0x0f, 0xb5, 0xfd, + 0xb1, 0xd0, 0x8c, 0x74, 0x49, 0xaf, 0xfd, 0x74, 0x33, 0xf8, 0xab, 0x5d, 0x12, 0xb3, 0x63, 0xa1, + 0xe3, 0x32, 0x83, 0x0f, 0xe0, 0x5b, 0x9d, 0x6c, 0x52, 0x56, 0xe9, 0x92, 0x5e, 0x2b, 0x6e, 0x5a, + 0x26, 0x52, 0xbc, 0x05, 0xcf, 0xe8, 0x2c, 0xd5, 0xbb, 0x93, 0xaf, 0x96, 0xbe, 0x71, 0x06, 0x22, + 0xc5, 0x7b, 0x80, 0xc5, 0x36, 0x5f, 0x7e, 0x26, 0x6b, 0x65, 0xd6, 0xac, 0xd6, 0x25, 0x3d, 0x3f, + 0xf6, 0x4a, 0x32, 0x56, 0x66, 0x8d, 0x0c, 0xdc, 0x42, 0x1d, 0xb7, 0xb9, 0x4a, 0x59, 0xbd, 0x74, + 0xbf, 0x4f, 0xbc, 0x03, 0xcf, 0x6c, 0x56, 0x99, 0xda, 0x1f, 0x76, 0x9a, 0x39, 0xe7, 0x9e, 0x05, + 0xfd, 0x2f, 0x02, 0xcd, 0x7f, 0x9f, 0xc5, 0x26, 0xb8, 0x73, 0xf9, 0x2a, 0xa3, 0x0f, 0x49, 0xaf, + 0xd0, 0x87, 0xc6, 0x50, 0xca, 0x68, 0x2e, 0x03, 0x4e, 0x09, 0x02, 0x38, 0x41, 0x34, 0x99, 0x88, + 0x19, 0xad, 0x60, 0x0b, 0xbc, 0x60, 0x3c, 0x0c, 0x43, 0x2e, 0x47, 0x9c, 0x56, 0x4f, 0xc1, 0x98, + 0x4f, 0xdf, 0x22, 0x39, 0xe5, 0xb4, 0x86, 0x08, 0xed, 0x20, 0x0a, 0x43, 0x1e, 0xcc, 0xc4, 0x3b, + 0x4f, 0xa6, 0x62, 0x44, 0xeb, 0x48, 0xc1, 0x7f, 0x11, 0x72, 0x18, 0x26, 0x97, 0x09, 0x07, 0xaf, + 0xa1, 0x73, 0x21, 0x76, 0xc8, 0x3d, 0x55, 0xcf, 0xd0, 0xce, 0x35, 0x16, 0x4e, 0x79, 0x83, 0xe7, + 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0xa2, 0x8a, 0x4f, 0x96, 0x01, 0x00, 0x00, +} diff --git a/consensus/proto/consensus.proto b/consensus/proto/consensus.proto new file mode 100644 index 000000000..2d23f3673 --- /dev/null +++ b/consensus/proto/consensus.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package consensus; + +enum MessageType { + UNKNOWN = 0; + ANNOUNCE = 1; + COMMIT = 2; + CHALLENGE = 3; + RESPONSE = 4; + COLLECTIVE_SIG = 5; + FINAL_COMMIT = 6; + FINAL_CHALLENGE = 7; + FINAL_RESPONSE = 8; +} + +message Message { + MessageType type = 1; + uint32 consensus_id = 2; + uint32 sender_id = 3; // TODO: make it public key + bytes block_hash = 4; + bytes payload = 5; + bytes signature = 6; +} diff --git a/utils/utils.go b/utils/utils.go index 9c910a485..12c38b9c7 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -26,19 +26,19 @@ func ConvertFixedDataIntoByteArray(data interface{}) []byte { // GetUniqueIDFromPeer ... // TODO(minhdoan): this is probably a hack, probably needs some strong non-collision hash. -func GetUniqueIDFromPeer(peer p2p.Peer) uint16 { +func GetUniqueIDFromPeer(peer p2p.Peer) uint32 { return GetUniqueIDFromIPPort(peer.IP, peer.Port) } // GetUniqueIDFromIPPort -- -func GetUniqueIDFromIPPort(ip, port string) uint16 { +func GetUniqueIDFromIPPort(ip, port string) uint32 { reg, err := regexp.Compile("[^0-9]+") if err != nil { log.Panic("Regex Compilation Failed", "err", err) } socketID := reg.ReplaceAllString(ip+port, "") // A integer Id formed by unique IP/PORT pair value, _ := strconv.Atoi(socketID) - return uint16(value) + return uint32(value) } // RunCmd runs command `name` with arguments `args`