Skip to content

Commit

Permalink
mweb: block deserialisation
Browse files Browse the repository at this point in the history
  • Loading branch information
losh11 committed Apr 19, 2023
1 parent 0fef156 commit b01a1d5
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 1 deletion.
66 changes: 66 additions & 0 deletions wire/msgblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const MaxBlockPayload = 4000000
// possibly fit into a block.
const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1

// mwebVer is the bit of the block header's version that indicates the
// presence of a MWEB.
const mwebVer = 0x20000000 // 1 << 29

// TxLoc holds locator data for the offset and length of where a transaction is
// located within a MsgBlock data buffer.
type TxLoc struct {
Expand Down Expand Up @@ -81,6 +85,7 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) er
return messageError("MsgBlock.BtcDecode", str)
}

var hasHogEx bool
msg.Transactions = make([]*MsgTx, 0, txCount)
for i := uint64(0); i < txCount; i++ {
tx := MsgTx{}
Expand All @@ -89,6 +94,15 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) er
return err
}
msg.Transactions = append(msg.Transactions, &tx)
hasHogEx = tx.IsHogEx
}

// The mwebVer mask indicates it may contain a MWEB after a HogEx.
// src/primitives/block.h: SERIALIZE_NO_MWEB
if msg.Header.Version&mwebVer != 0 && hasHogEx {
if err = parseMWEB(r); err != nil {
return err
}
}

return nil
Expand Down Expand Up @@ -288,3 +302,55 @@ func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
}
}

/// MWEB

func parseMWEB(blk io.Reader) error {
dec := newDecoder(blk)
// src/mweb/mweb_models.h - struct Block
// "A convenience wrapper around a possibly-null extension block.""
// OptionalPtr around a mw::Block. Read the option byte:
hasMWEB, err := dec.readByte()
if err != nil {
return fmt.Errorf("failed to check MWEB option byte: %w", err)
}
if hasMWEB == 0 {
return nil
}

// src/libmw/include/mw/models/block/Block.h - class Block
// (1) Header and (2) TxBody

// src/libmw/include/mw/models/block/Header.h - class Header
// height
if _, err = dec.readVLQ(); err != nil {
return fmt.Errorf("failed to decode MWEB height: %w", err)
}

// 3x Hash + 2x BlindingFactor
if err = dec.discardBytes(32*3 + 32*2); err != nil {
return fmt.Errorf("failed to decode MWEB junk: %w", err)
}

// Number of TXOs: outputMMRSize
if _, err = dec.readVLQ(); err != nil {
return fmt.Errorf("failed to decode TXO count: %w", err)
}

// Number of kernels: kernelMMRSize
if _, err = dec.readVLQ(); err != nil {
return fmt.Errorf("failed to decode kernel count: %w", err)
}

// TxBody
_, err = dec.readMWTXBody()
if err != nil {
return fmt.Errorf("failed to decode MWEB tx: %w", err)
}
// if len(kern0) > 0 {
// mwebTxID := chainhash.Hash(blake3.Sum256(kern0))
// fmt.Println(mwebTxID.String())
// }

return nil
}
103 changes: 102 additions & 1 deletion wire/msgblock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,43 @@ package wire

import (
"bytes"
_ "embed"
"io"
"reflect"
"testing"
"time"

"github.com/ltcsuite/ltcd/chaincfg/chainhash"
"github.com/davecgh/go-spew/spew"
"github.com/ltcsuite/ltcd/chaincfg/chainhash"
)

var (
// Testnet4 block 1821752 is pre-MWEB activation, 3 txns.
// But version 20000000.
//go:embed testdata/testnet4Block1821752.dat
block1821752 []byte

// Block 2215584 is the first with MW txns, a peg-in with witness version 9
// script, an integ tx with witness version 8 script, block version 20000000
// (with a MWEB), and 5 txns.
// 7e35fabe7b3c694ebeb0368a1a1c31e83962f3c5b4cc8dcede3ae94ed3deb306
//go:embed testdata/testnet4Block2215584.dat
block2215584 []byte

// Block 2321749 is version 20000000 with a MWEB, 4 txns, the last one being
// an integration / hogex txn that fails to decode.
// 57929846db4a92d937eb596354d10949e33c815ee45df0c9b3bbdfb283e15bcd
//go:embed testdata/testnet4Block2321749.dat
block2321749 []byte

// Block 2319633 is version 20000000 with a MWEB, 2 txns, one coinbase and
// one integration.
// e9fe2c6496aedefa8bf6529bdc5c1f9fd4af565ca4c98cab73e3a1f616fb3502
//go:embed testdata/testnet4Block2319633.dat
block2319633 []byte

//go:embed testdata/testnet4Block2215586.dat
block2215586 []byte
)

// TestBlock tests the MsgBlock API.
Expand Down Expand Up @@ -482,6 +512,77 @@ func TestBlockSerializeSize(t *testing.T) {
}
}

func TestDeserializeBlockBytes(t *testing.T) {
tests := []struct {
name string
blk []byte
wantHash string
wantNumTx int
wantLastTx string
}{
{
"block 1821752 pre-MWEB activation",
block1821752,
"ece484c02e84e4b1c551fbbdde3045e9096c970fbd3e31f2586b68d50dad6b24",
3,
"cb4d9d2d7ab7211ddf030a667d320fe499c849623e9d4a130e1901391e9d4947",
},
{
"block 2215584 MWEB",
block2215584,
"7e35fabe7b3c694ebeb0368a1a1c31e83962f3c5b4cc8dcede3ae94ed3deb306",
5,
"4c86658e64861c2f2b7fbbf26bbf7a6640ae3824d24293a009ad5ea1e8ab4418",
},
{
"block 2215586 MWEB",
block2215586,
"3000cc2076a568a8eb5f56a06112a57264446e2c7d2cca28cdc85d91820dfa17",
37,
"3a7299f5e6ee9975bdcc2d754ff5de3312d92db177b55c68753a1cdf9ce63a7c",
},
{
"block 2321749 MWEB",
block2321749,
"57929846db4a92d937eb596354d10949e33c815ee45df0c9b3bbdfb283e15bcd",
4,
"1bad5e78b145947d32eeeb1d24295891ba03359508d5f09921bada3be66bbe17",
},
{
"block 2319633 MWEB",
block2319633,
"e9fe2c6496aedefa8bf6529bdc5c1f9fd4af565ca4c98cab73e3a1f616fb3502",
2,
"3cd43df64e9382040eff0bf54ba1c2389d5111eb5ab0968ab7af67e3c30cac04",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var msg MsgBlock
r := bytes.NewReader(tt.blk)
err := msg.Deserialize(r)
if err != nil {
t.Fatal(err)
}

blkHash := msg.BlockHash()
if blkHash.String() != tt.wantHash {
t.Errorf("Wanted block hash %v, got %v", tt.wantHash, blkHash)
}

if len(msg.Transactions) != tt.wantNumTx {
t.Errorf("Wanted %d txns, found %d", tt.wantNumTx, len(msg.Transactions))
}

lastTxHash := msg.Transactions[len(msg.Transactions)-1].TxHash()
if lastTxHash.String() != tt.wantLastTx {
t.Errorf("Wanted last tx hash %v, got %v", tt.wantLastTx, lastTxHash)
}
})
}
}

// blockOne is the first block in the mainnet block chain.
var blockOne = MsgBlock{
Header: BlockHeader{
Expand Down
Binary file added wire/testdata/testnet4Block1821752.dat
Binary file not shown.
Binary file added wire/testdata/testnet4Block2215584.dat
Binary file not shown.
Binary file added wire/testdata/testnet4Block2215586.dat
Binary file not shown.
Binary file added wire/testdata/testnet4Block2319633.dat
Binary file not shown.
Binary file added wire/testdata/testnet4Block2321749.dat
Binary file not shown.

0 comments on commit b01a1d5

Please sign in to comment.