feat(p2p): CORE_SYNC_DATA type and command ID constants
Add CoreSyncData with MarshalSection/UnmarshalSection for portable storage roundtrip. Re-export Levin command IDs for the CryptoNote P2P protocol layer. Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
888a0b6fff
commit
3474a98f97
5 changed files with 176 additions and 2 deletions
7
go.mod
7
go.mod
|
|
@ -1,8 +1,11 @@
|
|||
module forge.lthn.ai/core/go-blockchain
|
||||
|
||||
go 1.25
|
||||
go 1.25.5
|
||||
|
||||
require golang.org/x/crypto v0.48.0
|
||||
require (
|
||||
forge.lthn.ai/core/go-p2p v0.0.0-00010101000000-000000000000
|
||||
golang.org/x/crypto v0.48.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.41.0 // indirect
|
||||
|
||||
|
|
|
|||
8
go.sum
8
go.sum
|
|
@ -1,4 +1,12 @@
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
22
p2p/commands.go
Normal file
22
p2p/commands.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
||||
//
|
||||
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package p2p implements the CryptoNote P2P protocol for the Lethean blockchain.
|
||||
package p2p
|
||||
|
||||
import "forge.lthn.ai/core/go-p2p/node/levin"
|
||||
|
||||
// Re-export command IDs from the levin package for convenience.
|
||||
const (
|
||||
CommandHandshake = levin.CommandHandshake
|
||||
CommandTimedSync = levin.CommandTimedSync
|
||||
CommandPing = levin.CommandPing
|
||||
CommandNewBlock = levin.CommandNewBlock
|
||||
CommandNewTransactions = levin.CommandNewTransactions
|
||||
CommandRequestObjects = levin.CommandRequestObjects
|
||||
CommandResponseObjects = levin.CommandResponseObjects
|
||||
CommandRequestChain = levin.CommandRequestChain
|
||||
CommandResponseChain = levin.CommandResponseChain
|
||||
)
|
||||
82
p2p/sync.go
Normal file
82
p2p/sync.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
||||
//
|
||||
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"forge.lthn.ai/core/go-blockchain/types"
|
||||
"forge.lthn.ai/core/go-p2p/node/levin"
|
||||
)
|
||||
|
||||
// CoreSyncData is the blockchain state exchanged during handshake and timed sync.
|
||||
type CoreSyncData struct {
|
||||
CurrentHeight uint64
|
||||
TopID types.Hash
|
||||
LastCheckpointHeight uint64
|
||||
CoreTime uint64
|
||||
ClientVersion string
|
||||
NonPruningMode bool
|
||||
}
|
||||
|
||||
// MarshalSection encodes CoreSyncData into a portable storage Section.
|
||||
func (d *CoreSyncData) MarshalSection() levin.Section {
|
||||
return levin.Section{
|
||||
"current_height": levin.Uint64Val(d.CurrentHeight),
|
||||
"top_id": levin.StringVal(d.TopID[:]),
|
||||
"last_checkpoint_height": levin.Uint64Val(d.LastCheckpointHeight),
|
||||
"core_time": levin.Uint64Val(d.CoreTime),
|
||||
"client_version": levin.StringVal([]byte(d.ClientVersion)),
|
||||
"non_pruning_mode_enabled": levin.BoolVal(d.NonPruningMode),
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalSection decodes CoreSyncData from a portable storage Section.
|
||||
func (d *CoreSyncData) UnmarshalSection(s levin.Section) error {
|
||||
if v, ok := s["current_height"]; ok {
|
||||
val, err := v.AsUint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.CurrentHeight = val
|
||||
}
|
||||
if v, ok := s["top_id"]; ok {
|
||||
blob, err := v.AsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(blob) == 32 {
|
||||
copy(d.TopID[:], blob)
|
||||
}
|
||||
}
|
||||
if v, ok := s["last_checkpoint_height"]; ok {
|
||||
val, err := v.AsUint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.LastCheckpointHeight = val
|
||||
}
|
||||
if v, ok := s["core_time"]; ok {
|
||||
val, err := v.AsUint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.CoreTime = val
|
||||
}
|
||||
if v, ok := s["client_version"]; ok {
|
||||
blob, err := v.AsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.ClientVersion = string(blob)
|
||||
}
|
||||
if v, ok := s["non_pruning_mode_enabled"]; ok {
|
||||
val, err := v.AsBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.NonPruningMode = val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
59
p2p/sync_test.go
Normal file
59
p2p/sync_test.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
||||
//
|
||||
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go-blockchain/types"
|
||||
"forge.lthn.ai/core/go-p2p/node/levin"
|
||||
)
|
||||
|
||||
func TestCoreSyncData_Good_Roundtrip(t *testing.T) {
|
||||
var topID types.Hash
|
||||
topID[0] = 0xCB
|
||||
topID[31] = 0x63
|
||||
|
||||
original := CoreSyncData{
|
||||
CurrentHeight: 6300,
|
||||
TopID: topID,
|
||||
LastCheckpointHeight: 0,
|
||||
CoreTime: 1708444800,
|
||||
ClientVersion: "Lethean/go-blockchain 0.1.0",
|
||||
NonPruningMode: true,
|
||||
}
|
||||
section := original.MarshalSection()
|
||||
data, err := levin.EncodeStorage(section)
|
||||
if err != nil {
|
||||
t.Fatalf("encode: %v", err)
|
||||
}
|
||||
decoded, err := levin.DecodeStorage(data)
|
||||
if err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
var got CoreSyncData
|
||||
if err := got.UnmarshalSection(decoded); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if got.CurrentHeight != original.CurrentHeight {
|
||||
t.Errorf("height: got %d, want %d", got.CurrentHeight, original.CurrentHeight)
|
||||
}
|
||||
if got.TopID != original.TopID {
|
||||
t.Errorf("top_id: got %x, want %x", got.TopID, original.TopID)
|
||||
}
|
||||
if got.ClientVersion != original.ClientVersion {
|
||||
t.Errorf("version: got %q, want %q", got.ClientVersion, original.ClientVersion)
|
||||
}
|
||||
if got.NonPruningMode != original.NonPruningMode {
|
||||
t.Errorf("pruning: got %v, want %v", got.NonPruningMode, original.NonPruningMode)
|
||||
}
|
||||
if got.LastCheckpointHeight != original.LastCheckpointHeight {
|
||||
t.Errorf("checkpoint: got %d, want %d", got.LastCheckpointHeight, original.LastCheckpointHeight)
|
||||
}
|
||||
if got.CoreTime != original.CoreTime {
|
||||
t.Errorf("core_time: got %d, want %d", got.CoreTime, original.CoreTime)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue