diff --git a/identitychain/identityblock.go b/identitychain/identityblock.go index 5fb55b132..395417b35 100644 --- a/identitychain/identityblock.go +++ b/identitychain/identityblock.go @@ -1,9 +1,70 @@ package identitychain -import "github.com/simple-rules/harmony-benchmark/p2p" +import ( + "bytes" + "crypto/sha256" + "encoding/gob" + "log" + "time" + + "github.com/simple-rules/harmony-benchmark/utils" + "github.com/simple-rules/harmony-benchmark/waitnode" +) // IdentityBlock has the information of one node type IdentityBlock struct { - Peer p2p.Peer + Timestamp int64 + PrevBlockHash [32]byte NumIdentities int32 + Identities []*waitnode.WaitNode +} + +// Serialize serializes the block +func (b *IdentityBlock) Serialize() []byte { + var result bytes.Buffer + encoder := gob.NewEncoder(&result) + err := encoder.Encode(b) + if err != nil { + log.Panic(err) + } + return result.Bytes() +} + +// DeserializeBlock deserializes a block +func DeserializeBlock(d []byte) *IdentityBlock { + var block IdentityBlock + decoder := gob.NewDecoder(bytes.NewReader(d)) + err := decoder.Decode(&block) + if err != nil { + log.Panic(err) + } + return &block +} + +// NewBlock creates and returns a new block. +func NewBlock(Identities []*waitnode.WaitNode, prevBlockHash [32]byte) *IdentityBlock { + block := &IdentityBlock{Timestamp: time.Now().Unix(), PrevBlockHash: prevBlockHash, NumIdentities: int32(len(Identities)), Identities: Identities} + return &block +} + +// CalculateBlockHash returns a hash of the block +func (b *IdentityBlock) CalculateBlockHash() []byte { + var hashes [][]byte + var blockHash [32]byte + hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(b.Timestamp)) + hashes = append(hashes, b.PrevBlockHash[:]) + for _, id := range b.Identities { + hashes = append(hashes, id) + } + hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(b.ShardId)) + blockHash = sha256.Sum256(bytes.Join(hashes, []byte{})) + return blockHash[:] +} + +// NewGenesisBlock creates and returns genesis Block. +func NewGenesisBlock() *IdentityBlock { + numTxs := 0 + var Ids []*waitnode.WaitNode + block := &IdentityBlock{Timestamp: time.Now().Unix(), PrevBlockHash: [32]byte{}, NumIdentities: 1, Identities: Ids} + return block } diff --git a/identitychain/identitychain.go b/identitychain/identitychain.go index ca3fc40b5..1e4114162 100644 --- a/identitychain/identitychain.go +++ b/identitychain/identitychain.go @@ -1,7 +1,6 @@ package identitychain import ( - "fmt" "net" "os" "sync" @@ -12,7 +11,7 @@ import ( ) var mutex sync.Mutex - +var IdentityPerBlock := 100000 // IdentityChain (Blockchain) keeps Identities per epoch, currently centralized! type IdentityChain struct { Identities []*IdentityBlock @@ -20,10 +19,67 @@ type IdentityChain struct { log log.Logger } -//IdentityChainHandler handles transactions +//IdentityChainHandler handles registration of new Identities func (IDC *IdentityChain) IdentityChainHandler(conn net.Conn) { - fmt.Println("yay") + // Read p2p message payload + content, err := p2p.ReadMessageContent(conn) + if err != nil { + IDC.log.Error("Read p2p data failed", "err", err, "node", node) + return + } + + msgCategory, err := proto.GetMessageCategory(content) + if err != nil { + IDC.log.Error("Read node type failed", "err", err, "node", node) + return + } + + msgType, err := proto.GetMessageType(content) + if err != nil { + IDC.log.Error("Read action type failed", "err", err, "node", node) + return + } + + msgPayload, err := proto.GetMessagePayload(content) + if err != nil { + IDC.log.Error("Read message payload failed", "err", err, "node", node) + return + } + content, err := p2p.ReadMessageContent(conn) + if err != nil { + IDC.log.Error("Read p2p data failed", "err", err, "node", node) + return + } +} + +// GetLatestBlock gests the latest block at the end of the chain +func (IDC *IdentityChain) GetLatestBlock() *IdentityBlock { + if len(IDC.Identities) == 0 { + return nil + } + return IDC.Identities[len(IDC.Identities)-1] } + +//CreateNewBlock is to create the Blocks to be added to the chain +func (IDC *IdentityChain) MakeNewBlock() *IdentityBlock { + + if len(IDC.Identities) == 0 { + return NewGenesisBlock() + } + //If there are no more Identities registring the blockchain is dead + if len(IDC.PendingIdentities) == 0 { + // This is abd, because previous block might not be alive + return IDC.GetLatestBlock() + } + prevBlock := IDC.GetLatestBlock() + NewIdentities := IDC.PendingIdentities[:IdentityPerBlock] + IDC.PendingIdentities = IDC.PendingIdentities[IdentityPerBlock]: + //All other blocks are dropped. + IDBlock = NewBlock(NewIdentities,prevBlock.CalculateBlockHash()) + IDC.Identities = append(IDBlock,IDC.Identities) + } +} + func (IDC *IdentityChain) listenOnPort(port string) { listen, err := net.Listen("tcp4", ":"+port) defer listen.Close() @@ -49,6 +105,5 @@ func main() { mutex.Lock() IDC.Identities = append(IDC.Identities, genesisBlock) mutex.Unlock() - }() } diff --git a/proto/common.go b/proto/common.go index fd697013b..c3b2f5f1a 100644 --- a/proto/common.go +++ b/proto/common.go @@ -24,10 +24,12 @@ n - 2 bytes - actual message payload // The message category enum type MessageCategory byte +//CONSENSUS and other message categories const ( CONSENSUS MessageCategory = iota NODE CLIENT + IDENTITY // TODO: add more types ) diff --git a/proto/identity/identity.go b/proto/identity/identity.go new file mode 100644 index 000000000..95ac0c652 --- /dev/null +++ b/proto/identity/identity.go @@ -0,0 +1,42 @@ +package identity + +import ( + "errors" +) + +// the number of bytes consensus message type occupies +const IDENTITY_MESSAGE_TYPE_BYTES = 1 + +type MessageType int + +const ( + REGISTER MessageType = iota +) + +// Returns string name for the MessageType enum +func (msgType MessageType) String() string { + names := [...]string{ + "REGISTER", + } + + if msgType < REGISTER || msgType > REGISTER { + return "Unknown" + } + return names[msgType] +} + +// GetIdentityMessageType Get the consensus message type from the identity message +func GetIdentityMessageType(message []byte) (MessageType, error) { + if len(message) < 1 { + return 0, errors.New("Failed to get consensus message type: no data available.") + } + return MessageType(message[0]), nil +} + +// GetIdentityMessagePayload message payload from the identity message +func GetIdentityMessagePayload(message []byte) ([]byte, error) { + if len(message) < 2 { + return []byte{}, errors.New("Failed to get consensus message payload: no data available.") + } + return message[IDENTITY_MESSAGE_TYPE_BYTES:], nil +}