Update go.mod module line, all require/replace directives, and every .go import path from forge.lthn.ai/core/go-blockchain to dappco.re/go/core/blockchain. Add replace directives to bridge dappco.re paths to existing forge.lthn.ai registry during migration. Update CLAUDE.md, README, and docs to reflect the new module path. Co-Authored-By: Virgil <virgil@lethean.io>
178 lines
4.5 KiB
Go
178 lines
4.5 KiB
Go
// 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 wire
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"dappco.re/go/core/blockchain/types"
|
|
)
|
|
|
|
// testnetGenesisHeader returns the genesis block header for the Lethean testnet.
|
|
func testnetGenesisHeader() types.BlockHeader {
|
|
return types.BlockHeader{
|
|
MajorVersion: 1,
|
|
Nonce: 101011010221, // CURRENCY_FORMATION_VERSION(100) + 101011010121
|
|
PrevID: types.Hash{}, // all zeros
|
|
MinorVersion: 0,
|
|
Timestamp: 1770897600, // 2026-02-12 12:00:00 UTC
|
|
Flags: 0,
|
|
}
|
|
}
|
|
|
|
func TestEncodeBlockHeader_Good(t *testing.T) {
|
|
h := testnetGenesisHeader()
|
|
|
|
var buf bytes.Buffer
|
|
enc := NewEncoder(&buf)
|
|
EncodeBlockHeader(enc, &h)
|
|
if enc.Err() != nil {
|
|
t.Fatalf("encode error: %v", enc.Err())
|
|
}
|
|
|
|
data := buf.Bytes()
|
|
|
|
// Verify structure:
|
|
// byte 0: major_version = 0x01
|
|
// bytes 1-8: nonce LE
|
|
// bytes 9-40: prev_id (32 zeros)
|
|
// byte 41: minor_version varint = 0x00
|
|
// bytes 42+: timestamp varint
|
|
// last byte: flags = 0x00
|
|
|
|
if data[0] != 0x01 {
|
|
t.Errorf("major_version: got 0x%02x, want 0x01", data[0])
|
|
}
|
|
if data[len(data)-1] != 0x00 {
|
|
t.Errorf("flags: got 0x%02x, want 0x00", data[len(data)-1])
|
|
}
|
|
}
|
|
|
|
func TestBlockHeaderRoundTrip_Good(t *testing.T) {
|
|
h := testnetGenesisHeader()
|
|
|
|
var buf bytes.Buffer
|
|
enc := NewEncoder(&buf)
|
|
EncodeBlockHeader(enc, &h)
|
|
if enc.Err() != nil {
|
|
t.Fatalf("encode error: %v", enc.Err())
|
|
}
|
|
|
|
dec := NewDecoder(bytes.NewReader(buf.Bytes()))
|
|
got := DecodeBlockHeader(dec)
|
|
if dec.Err() != nil {
|
|
t.Fatalf("decode error: %v", dec.Err())
|
|
}
|
|
|
|
if got.MajorVersion != h.MajorVersion {
|
|
t.Errorf("MajorVersion: got %d, want %d", got.MajorVersion, h.MajorVersion)
|
|
}
|
|
if got.Nonce != h.Nonce {
|
|
t.Errorf("Nonce: got %d, want %d", got.Nonce, h.Nonce)
|
|
}
|
|
if got.PrevID != h.PrevID {
|
|
t.Errorf("PrevID: got %x, want %x", got.PrevID, h.PrevID)
|
|
}
|
|
if got.MinorVersion != h.MinorVersion {
|
|
t.Errorf("MinorVersion: got %d, want %d", got.MinorVersion, h.MinorVersion)
|
|
}
|
|
if got.Timestamp != h.Timestamp {
|
|
t.Errorf("Timestamp: got %d, want %d", got.Timestamp, h.Timestamp)
|
|
}
|
|
if got.Flags != h.Flags {
|
|
t.Errorf("Flags: got %d, want %d", got.Flags, h.Flags)
|
|
}
|
|
}
|
|
|
|
func TestBlockRoundTrip_Good(t *testing.T) {
|
|
// Build the genesis block and round-trip it through EncodeBlock/DecodeBlock.
|
|
rawTx := testnetGenesisRawTx()
|
|
dec := NewDecoder(bytes.NewReader(rawTx))
|
|
minerTx := DecodeTransaction(dec)
|
|
if dec.Err() != nil {
|
|
t.Fatalf("decode miner tx: %v", dec.Err())
|
|
}
|
|
|
|
block := types.Block{
|
|
BlockHeader: testnetGenesisHeader(),
|
|
MinerTx: minerTx,
|
|
}
|
|
|
|
// Encode.
|
|
var buf bytes.Buffer
|
|
enc := NewEncoder(&buf)
|
|
EncodeBlock(enc, &block)
|
|
if enc.Err() != nil {
|
|
t.Fatalf("encode error: %v", enc.Err())
|
|
}
|
|
|
|
// Decode.
|
|
dec2 := NewDecoder(bytes.NewReader(buf.Bytes()))
|
|
got := DecodeBlock(dec2)
|
|
if dec2.Err() != nil {
|
|
t.Fatalf("decode error: %v", dec2.Err())
|
|
}
|
|
|
|
// Re-encode and compare bytes.
|
|
var rtBuf bytes.Buffer
|
|
enc2 := NewEncoder(&rtBuf)
|
|
EncodeBlock(enc2, &got)
|
|
if enc2.Err() != nil {
|
|
t.Fatalf("re-encode error: %v", enc2.Err())
|
|
}
|
|
if !bytes.Equal(rtBuf.Bytes(), buf.Bytes()) {
|
|
t.Errorf("block round-trip mismatch")
|
|
}
|
|
|
|
// Verify block hash is unchanged after round-trip.
|
|
if BlockHash(&got) != BlockHash(&block) {
|
|
t.Errorf("block hash changed after round-trip")
|
|
}
|
|
}
|
|
|
|
func TestBlockWithTxHashesRoundTrip_Good(t *testing.T) {
|
|
block := types.Block{
|
|
BlockHeader: testnetGenesisHeader(),
|
|
MinerTx: types.Transaction{
|
|
Version: 1,
|
|
Vin: []types.TxInput{types.TxInputGenesis{Height: 0}},
|
|
Vout: []types.TxOutput{types.TxOutputBare{
|
|
Amount: 1000,
|
|
Target: types.TxOutToKey{Key: types.PublicKey{0xAA}},
|
|
}},
|
|
Extra: EncodeVarint(0),
|
|
Attachment: EncodeVarint(0),
|
|
},
|
|
TxHashes: []types.Hash{
|
|
{0x01, 0x02, 0x03},
|
|
{0xDE, 0xAD, 0xBE, 0xEF},
|
|
},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
enc := NewEncoder(&buf)
|
|
EncodeBlock(enc, &block)
|
|
if enc.Err() != nil {
|
|
t.Fatalf("encode error: %v", enc.Err())
|
|
}
|
|
|
|
dec := NewDecoder(bytes.NewReader(buf.Bytes()))
|
|
got := DecodeBlock(dec)
|
|
if dec.Err() != nil {
|
|
t.Fatalf("decode error: %v", dec.Err())
|
|
}
|
|
|
|
if len(got.TxHashes) != 2 {
|
|
t.Fatalf("tx_hashes count: got %d, want 2", len(got.TxHashes))
|
|
}
|
|
if got.TxHashes[0] != block.TxHashes[0] {
|
|
t.Errorf("tx_hashes[0]: got %x, want %x", got.TxHashes[0], block.TxHashes[0])
|
|
}
|
|
if got.TxHashes[1] != block.TxHashes[1] {
|
|
t.Errorf("tx_hashes[1]: got %x, want %x", got.TxHashes[1], block.TxHashes[1])
|
|
}
|
|
}
|