From e9f9354b86e5ee26b6b389d536595817c05b26fb Mon Sep 17 00:00:00 2001 From: anthdm Date: Tue, 30 Jan 2018 11:56:36 +0100 Subject: [PATCH] added core block type --- README.md | 4 +-- pkg/core/block.go | 28 ++++++++++++++++ pkg/core/transaction.go | 4 +++ pkg/network/message.go | 7 ++++ pkg/network/payload/inventory.go | 36 ++++++++++++++++++--- pkg/network/payload/inventory_test.go | 32 ++++++++++++++++++ pkg/network/server.go | 18 +++++++++++ pkg/util/{uint256.go => types.go} | 6 +++- pkg/util/{uint256_test.go => types_test.go} | 0 9 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 pkg/core/block.go create mode 100644 pkg/core/transaction.go create mode 100644 pkg/network/payload/inventory_test.go rename pkg/util/{uint256.go => types.go} (84%) rename pkg/util/{uint256_test.go => types_test.go} (100%) diff --git a/README.md b/README.md index 1449ce4be..e248c70ab 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

NEO-GO

- Node and SDK for the NEO blockchain written in the Go language. + Node and SDK for the NEO blockchain written in the Go language.

@@ -20,7 +20,7 @@ ### Long term project goals Full port of the original C# [NEO project](https://github.com/neo-project). A complete toolkit for the NEO blockchain. -- Full server (consensus, RPC and bookkeeping) nodes. +- Full server (consensus and RPC) nodes. - RPC client - build, compile and deploy smart contracts with the Go vm diff --git a/pkg/core/block.go b/pkg/core/block.go new file mode 100644 index 000000000..67057569d --- /dev/null +++ b/pkg/core/block.go @@ -0,0 +1,28 @@ +package core + +import ( + . "github.com/anthdm/neo-go/pkg/util" +) + +// Block represents one block in the chain. +type Block struct { + Version uint32 + // hash of the previous block. + PrevBlock Uint256 + // Root hash of a transaction list. + MerkleRoot Uint256 + // timestamp + Timestamp uint32 + // height of the block + Height uint32 + // Random number + Nonce uint64 + // contract addresss of the next miner + NextMiner Uint160 + // seperator ? fixed to 1 + _sep uint8 + // Script used to validate the block + Script []byte + // transaction list + Transactions []*Transaction +} diff --git a/pkg/core/transaction.go b/pkg/core/transaction.go new file mode 100644 index 000000000..905a7b158 --- /dev/null +++ b/pkg/core/transaction.go @@ -0,0 +1,4 @@ +package core + +// Transaction is a process recorded in the NEO system. +type Transaction struct{} diff --git a/pkg/network/message.go b/pkg/network/message.go index eeec5a59c..3df2e0305 100644 --- a/pkg/network/message.go +++ b/pkg/network/message.go @@ -83,6 +83,7 @@ const ( cmdGetData = "getdata" cmdBlock = "block" cmdTX = "tx" + cmdConsensus = "consensus" ) func newMessage(magic NetMode, cmd commandType, p payload.Payload) *Message { @@ -137,6 +138,8 @@ func (m *Message) commandType() commandType { return cmdBlock case "tx": return cmdTX + case "consensus": + return cmdConsensus default: return "" } @@ -149,6 +152,8 @@ func (m *Message) decode(r io.Reader) error { binary.Read(r, binary.LittleEndian, &m.Length) binary.Read(r, binary.LittleEndian, &m.Checksum) + fmt.Println(cmdByteArrayToString(m.Command)) + // return if their is no payload. if m.Length == 0 { return nil @@ -164,6 +169,8 @@ func (m *Message) decodePayload(r io.Reader) error { return err } + fmt.Printf("The length of the payload is %d\n", n) + if uint32(n) != m.Length { return fmt.Errorf("expected to have read exactly %d bytes got %d", m.Length, n) } diff --git a/pkg/network/payload/inventory.go b/pkg/network/payload/inventory.go index 980433865..306995016 100644 --- a/pkg/network/payload/inventory.go +++ b/pkg/network/payload/inventory.go @@ -27,6 +27,11 @@ func (i InventoryType) String() string { } } +// Valid returns true if the inventory (type) is known. +func (i InventoryType) Valid() bool { + return i == BlockType || i == TXType || i == ConsensusType +} + // List of valid InventoryTypes. const ( BlockType InventoryType = 0x01 // 1 @@ -39,7 +44,15 @@ type Inventory struct { // Type if the object hash. Type InventoryType // The hash of the object (uint256). - Hash Uint256 + Hashes []Uint256 +} + +// NewInventory return a pointer to an Inventory. +func NewInventory(typ InventoryType, hashes []Uint256) *Inventory { + return &Inventory{ + Type: typ, + Hashes: hashes, + } } // DecodeBinary implements the Payload interface. @@ -50,15 +63,30 @@ func (p *Inventory) DecodeBinary(r io.Reader) error { var listLen uint8 err := binary.Read(r, binary.LittleEndian, &p.Type) err = binary.Read(r, binary.LittleEndian, &listLen) - err = binary.Read(r, binary.LittleEndian, &p.Hash) + + p.Hashes = make([]Uint256, listLen) + for i := 0; i < int(listLen); i++ { + if err := binary.Read(r, binary.LittleEndian, &p.Hashes[i]); err != nil { + return err + } + } return err } // EncodeBinary implements the Payload interface. func (p *Inventory) EncodeBinary(w io.Writer) error { - // TODO - return nil + listLen := uint8(len(p.Hashes)) + err := binary.Write(w, binary.LittleEndian, p.Type) + err = binary.Write(w, binary.LittleEndian, listLen) + + for i := 0; i < len(p.Hashes); i++ { + if err := binary.Write(w, binary.LittleEndian, p.Hashes[i]); err != nil { + return err + } + } + + return err } // Size implements the Payloader interface. diff --git a/pkg/network/payload/inventory_test.go b/pkg/network/payload/inventory_test.go new file mode 100644 index 000000000..774e33017 --- /dev/null +++ b/pkg/network/payload/inventory_test.go @@ -0,0 +1,32 @@ +package payload + +import ( + "bytes" + "crypto/sha256" + "reflect" + "testing" + + . "github.com/anthdm/neo-go/pkg/util" +) + +func TestInventoryEncodeDecode(t *testing.T) { + hashes := []Uint256{ + sha256.Sum256([]byte("a")), + sha256.Sum256([]byte("b")), + } + inv := NewInventory(BlockType, hashes) + + buf := new(bytes.Buffer) + if err := inv.EncodeBinary(buf); err != nil { + t.Fatal(err) + } + + invDecode := &Inventory{} + if err := invDecode.DecodeBinary(buf); err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(inv, invDecode) { + t.Fatalf("expected both inventories to be equal %v and %v", inv, invDecode) + } +} diff --git a/pkg/network/server.go b/pkg/network/server.go index 4b2680431..ceba713b2 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -189,9 +189,11 @@ func (s *Server) processMessage(msg *Message, peer *Peer) error { case cmdHeaders: case cmdGetBlocks: case cmdInv: + return s.handleInvCmd(msg.Payload.(*payload.Inventory), peer) case cmdGetData: case cmdBlock: case cmdTX: + case cmdConsensus: default: return fmt.Errorf("invalid RPC command received: %s", command) } @@ -241,6 +243,22 @@ func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error return nil } +func (s *Server) handleInvCmd(inv *payload.Inventory, peer *Peer) error { + if !inv.Type.Valid() { + return fmt.Errorf("invalid inventory type: %s", inv.Type) + } + if len(inv.Hashes) == 0 { + return nil + } + + payload := payload.NewInventory(inv.Type, inv.Hashes) + msg := newMessage(s.net, cmdGetData, payload) + + peer.send <- msg + + return nil +} + func (s *Server) peerAlreadyConnected(addr net.Addr) bool { // TODO: check for race conditions //s.mtx.RLock() diff --git a/pkg/util/uint256.go b/pkg/util/types.go similarity index 84% rename from pkg/util/uint256.go rename to pkg/util/types.go index d82e19877..51588988e 100644 --- a/pkg/util/uint256.go +++ b/pkg/util/types.go @@ -7,7 +7,8 @@ import ( "fmt" ) -// Uint256 ... +// Uint256 is a 32 byte long unsigned integer. +// Commonly used to store hashes. type Uint256 [32]uint8 // Uint256FromBytes return an Uint256 from a byte slice. @@ -44,3 +45,6 @@ func (u Uint256) ToSlice() []byte { func (u Uint256) String() string { return hex.EncodeToString(u.ToSlice()) } + +// Uint160 is a 20 byte long unsigned integer +type Uint160 [20]uint8 diff --git a/pkg/util/uint256_test.go b/pkg/util/types_test.go similarity index 100% rename from pkg/util/uint256_test.go rename to pkg/util/types_test.go