1// SPDX-License-Identifier: ISC
2// Copyright (c) 2014-2020 Bitmark Inc.
3// Use of this source code is governed by an ISC
4// license that can be found in the LICENSE file.
5
6package transactionrecord_test
7
8import (
9	"bytes"
10	"encoding/json"
11	"reflect"
12	"testing"
13
14	"golang.org/x/crypto/ed25519"
15
16	"github.com/bitmark-inc/bitmarkd/currency"
17	"github.com/bitmark-inc/bitmarkd/fault"
18	"github.com/bitmark-inc/bitmarkd/merkle"
19	"github.com/bitmark-inc/bitmarkd/transactionrecord"
20	"github.com/bitmark-inc/bitmarkd/util"
21)
22
23// test the packing/unpacking of base record
24//
25// ensures that pack->unpack returns the same original value
26func TestPackBlockFoundation(t *testing.T) {
27
28	proofedByAccount := makeAccount(proofedBy.publicKey)
29
30	r := transactionrecord.BlockFoundation{
31		Version: 1,
32		Payments: currency.Map{
33			currency.Bitcoin:  "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn",
34			currency.Litecoin: "mmCKZS7toE69QgXNs1JZcjW6LFj8LfUbz6",
35		},
36		Owner: proofedByAccount,
37		Nonce: 0x12345678,
38	}
39
40	expected := []byte{
41		0x06, 0x01, 0x48, 0x01, 0x22, 0x6d, 0x69, 0x70,
42		0x63, 0x42, 0x62, 0x46, 0x67, 0x39, 0x67, 0x4d,
43		0x69, 0x43, 0x68, 0x38, 0x31, 0x4b, 0x6a, 0x38,
44		0x74, 0x71, 0x71, 0x64, 0x67, 0x6f, 0x5a, 0x75,
45		0x62, 0x31, 0x5a, 0x4a, 0x52, 0x66, 0x6e, 0x02,
46		0x22, 0x6d, 0x6d, 0x43, 0x4b, 0x5a, 0x53, 0x37,
47		0x74, 0x6f, 0x45, 0x36, 0x39, 0x51, 0x67, 0x58,
48		0x4e, 0x73, 0x31, 0x4a, 0x5a, 0x63, 0x6a, 0x57,
49		0x36, 0x4c, 0x46, 0x6a, 0x38, 0x4c, 0x66, 0x55,
50		0x62, 0x7a, 0x36, 0x21, 0x13, 0x55, 0xb2, 0x98,
51		0x88, 0x17, 0xf7, 0xea, 0xec, 0x37, 0x74, 0x1b,
52		0x82, 0x44, 0x71, 0x63, 0xca, 0xaa, 0x5a, 0x9d,
53		0xb2, 0xb6, 0xf0, 0xce, 0x72, 0x26, 0x26, 0x33,
54		0x8e, 0x5e, 0x3f, 0xd7, 0xf7, 0xf8, 0xac, 0xd1,
55		0x91, 0x01,
56	}
57
58	expectedTxId := merkle.Digest{
59		0xc6, 0xa6, 0xca, 0x7b, 0xc1, 0xab, 0x3c, 0xac,
60		0x1f, 0x34, 0x5b, 0x2b, 0xa8, 0x1d, 0x20, 0x8d,
61		0x61, 0x65, 0x83, 0xd0, 0x5a, 0x22, 0xd9, 0xcb,
62		0x77, 0x47, 0x2d, 0x9c, 0x22, 0x49, 0x1a, 0x22,
63	}
64
65	// manually sign the record and attach signature to "expected"
66	signature := ed25519.Sign(proofedBy.privateKey, expected)
67	r.Signature = signature
68	//t.Logf("signature: %#v", r.Signature)
69	l := util.ToVarint64(uint64(len(signature)))
70	expected = append(expected, l...)
71	expected = append(expected, signature...)
72
73	// test the packer
74	packed, err := r.Pack(proofedByAccount)
75	if nil != err {
76		if nil != packed {
77			t.Errorf("partial packed:\n%s", util.FormatBytes("expected", packed))
78		}
79		t.Fatalf("pack error: %s", err)
80	}
81
82	// if either of above fail we will have the message _without_ a signature
83	if !bytes.Equal(packed, expected) {
84		t.Errorf("pack record: %x  expected: %x", packed, expected)
85		t.Errorf("*** GENERATED Packed:\n%s", util.FormatBytes("expected", packed))
86		t.Fatal("fatal error")
87	}
88
89	// check the record type
90	if transactionrecord.BlockFoundationTag != packed.Type() {
91		t.Fatalf("pack record type: %x  expected: %x", packed.Type(), transactionrecord.BlockFoundationTag)
92	}
93
94	t.Logf("Packed length: %d bytes", len(packed))
95
96	// check txIds
97	txId := packed.MakeLink()
98
99	if txId != expectedTxId {
100		t.Errorf("pack tx id: %#v  expected: %#v", txId, expectedTxId)
101		t.Errorf("*** GENERATED tx id:\n%s", util.FormatBytes("expectedTxId", txId[:]))
102	}
103
104	// test the unpacker
105	unpacked, n, err := packed.Unpack(true)
106	if nil != err {
107		t.Fatalf("unpack error: %s", err)
108	}
109
110	if len(packed) != n {
111		t.Errorf("did not unpack all data: only used: %d of: %d bytes", n, len(packed))
112	}
113
114	blockFoundation, ok := unpacked.(*transactionrecord.BlockFoundation)
115	if !ok {
116		t.Fatalf("did not unpack to BlockFoundation")
117	}
118
119	// display a JSON version for information
120	item := struct {
121		TxId            merkle.Digest
122		BlockFoundation *transactionrecord.BlockFoundation
123	}{
124		TxId:            txId,
125		BlockFoundation: blockFoundation,
126	}
127	b, err := json.MarshalIndent(item, "", "  ")
128	if nil != err {
129		t.Fatalf("json error: %s", err)
130	}
131
132	t.Logf("BlockFoundation: JSON: %s", b)
133
134	// check that structure is preserved through Pack/Unpack
135	// note reg is a pointer here
136	if !reflect.DeepEqual(r, *blockFoundation) {
137		t.Errorf("different, original: %v  recovered: %v", r, *blockFoundation)
138	}
139	checkPackedData(t, "block foundation", packed)
140}
141
142// test the pack failure on trying to use the zero public key
143func TestPackBlockFoundationWithZeroAccount(t *testing.T) {
144
145	proofedByAccount := makeAccount(theZeroKey.publicKey)
146
147	r := transactionrecord.BlockFoundation{
148		Version: 1,
149		Payments: currency.Map{
150			currency.Bitcoin:  "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn",
151			currency.Litecoin: "mmCKZS7toE69QgXNs1JZcjW6LFj8LfUbz6",
152		},
153		Owner:     proofedByAccount,
154		Nonce:     0x12345678,
155		Signature: []byte{1, 2, 3, 4},
156	}
157
158	// test the packer
159	_, err := r.Pack(proofedByAccount)
160	if nil == err {
161		t.Fatalf("pack should have failed")
162	}
163	if fault.InvalidOwnerOrRegistrant != err {
164		t.Fatalf("unexpected pack error: %s", err)
165	}
166}
167