From e36b28ab6a70f94d7060249dd13f6f545e2155a6 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 27 Dec 2024 12:51:45 +0300 Subject: [PATCH] capability: add ArchivalNode, fix #3776 This will be used to differentiate full history nodes from state only. Currently it's just a definition, we can not use it safely on current networks because nodes will refuse this Version, so actual code using the attribute will be added in newer versions. Signed-off-by: Roman Khimov --- pkg/network/capability/capability.go | 18 ++++++++++++++++++ pkg/network/capability/capability_test.go | 12 ++++++++++++ pkg/network/capability/type.go | 5 +++++ pkg/network/payload/version_test.go | 4 ++++ 4 files changed, 39 insertions(+) diff --git a/pkg/network/capability/capability.go b/pkg/network/capability/capability.go index bc0fa101d3..21f0bc7900 100644 --- a/pkg/network/capability/capability.go +++ b/pkg/network/capability/capability.go @@ -64,6 +64,8 @@ type Capability struct { func (c *Capability) DecodeBinary(br *io.BinReader) { c.Type = Type(br.ReadB()) switch c.Type { + case ArchivalNode: + c.Data = &Archival{} case FullNode: c.Data = &Node{} case TCPServer, WSServer: @@ -115,6 +117,22 @@ func (s *Server) EncodeBinary(bw *io.BinWriter) { bw.WriteU16LE(s.Port) } +// Archival represents an archival node that stores all blocks. +type Archival struct{} + +// DecodeBinary implements io.Serializable. +func (a *Archival) DecodeBinary(br *io.BinReader) { + var zero = br.ReadB() // Zero-length byte array as per Unknown. + if zero != 0 { + br.Err = errors.New("archival capability with non-zero data") + } +} + +// EncodeBinary implements io.Serializable. +func (a *Archival) EncodeBinary(bw *io.BinWriter) { + bw.WriteB(0) +} + // Unknown represents an unknown capability with some data. Other nodes can // decode it even if they can't interpret it. This is not expected to be used // for sending data directly (proper new types should be used), but it allows diff --git a/pkg/network/capability/capability_test.go b/pkg/network/capability/capability_test.go index 52649f9a84..62ef988118 100644 --- a/pkg/network/capability/capability_test.go +++ b/pkg/network/capability/capability_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/nspcc-dev/neo-go/internal/testserdes" + "github.com/stretchr/testify/require" ) func TestUnknownEncodeDecode(t *testing.T) { @@ -13,3 +14,14 @@ func TestUnknownEncodeDecode(t *testing.T) { ) testserdes.EncodeDecodeBinary(t, &u, &ud) } + +func TestArchivalEncodeDecode(t *testing.T) { + var ( + a = Archival{} + ad Archival + ) + testserdes.EncodeDecodeBinary(t, &a, &ad) + + var bad = []byte{0x02, 0x55, 0xaa} // Two-byte var-encoded string. + require.Error(t, testserdes.DecodeBinary(bad, &ad)) +} diff --git a/pkg/network/capability/type.go b/pkg/network/capability/type.go index a20336e40a..161a49f548 100644 --- a/pkg/network/capability/type.go +++ b/pkg/network/capability/type.go @@ -10,6 +10,11 @@ const ( WSServer Type = 0x02 // FullNode represents a node that has complete current state. FullNode Type = 0x10 + // ArchivalNode represents a node that stores full block history. + // These nodes can be used for P2P synchronization from genesis + // (FullNode can cut the tail and may not respond to requests for + // old (wrt MaxTraceableBlocks) blocks). + ArchivalNode Type = 0x11 // 0xf0-0xff are reserved for private experiments. ReservedFirst Type = 0xf0 diff --git a/pkg/network/payload/version_test.go b/pkg/network/payload/version_test.go index a18ac3d329..45315e6980 100644 --- a/pkg/network/payload/version_test.go +++ b/pkg/network/payload/version_test.go @@ -29,6 +29,10 @@ func TestVersionEncodeDecode(t *testing.T) { Port: wsPort, }, }, + { + Type: capability.ArchivalNode, + Data: &capability.Archival{}, + }, { Type: 0xff, Data: &capability.Unknown{},