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/fault"
17	"github.com/bitmark-inc/bitmarkd/merkle"
18	"github.com/bitmark-inc/bitmarkd/transactionrecord"
19	"github.com/bitmark-inc/bitmarkd/util"
20)
21
22// test the packing/unpacking of Share grant record
23//
24// ensures that pack->unpack returns the same original value
25func TestPackShareGrant(t *testing.T) {
26
27	ownerOneAccount := makeAccount(ownerOne.publicKey)
28	ownerTwoAccount := makeAccount(ownerTwo.publicKey)
29
30	var shareId merkle.Digest
31	err := merkleDigestFromLE("630c041cd1f586bcb9097e816189185c1e0379f67bbfc2f0626724f542047873", &shareId)
32	if nil != err {
33		t.Fatalf("hex to share error: %s", err)
34	}
35
36	r := transactionrecord.ShareGrant{
37		ShareId:   shareId,
38		Quantity:  100,
39		Owner:     ownerOneAccount,
40		Recipient: ownerTwoAccount,
41	}
42
43	expected := []byte{
44		0x09, 0x20, 0x63, 0x0c, 0x04, 0x1c, 0xd1, 0xf5,
45		0x86, 0xbc, 0xb9, 0x09, 0x7e, 0x81, 0x61, 0x89,
46		0x18, 0x5c, 0x1e, 0x03, 0x79, 0xf6, 0x7b, 0xbf,
47		0xc2, 0xf0, 0x62, 0x67, 0x24, 0xf5, 0x42, 0x04,
48		0x78, 0x73, 0x64, 0x21, 0x13, 0x27, 0x64, 0x0e,
49		0x4a, 0xab, 0x92, 0xd8, 0x7b, 0x4a, 0x6a, 0x2f,
50		0x30, 0xb8, 0x81, 0xf4, 0x49, 0x29, 0xf8, 0x66,
51		0x04, 0x3a, 0x84, 0x1c, 0x38, 0x14, 0xb1, 0x66,
52		0xb8, 0x89, 0x44, 0xb0, 0x92, 0x21, 0x13, 0xa1,
53		0x36, 0x32, 0xd5, 0x42, 0x5a, 0xed, 0x3a, 0x6b,
54		0x62, 0xe2, 0xbb, 0x6d, 0xe4, 0xc9, 0x59, 0x48,
55		0x41, 0xc1, 0x5b, 0x70, 0x15, 0x69, 0xec, 0x99,
56		0x99, 0xdc, 0x20, 0x1c, 0x35, 0xf7, 0xb3, 0x00,
57	}
58
59	expectedTxId := merkle.Digest{
60		0x26, 0x65, 0xce, 0x93, 0x0e, 0x8b, 0x0d, 0xe6,
61		0x60, 0x58, 0x0d, 0xfa, 0xff, 0x05, 0x00, 0xb0,
62		0x9d, 0xf9, 0xfc, 0xe8, 0x90, 0x93, 0x1b, 0xca,
63		0x3b, 0x10, 0x1d, 0x3f, 0xb6, 0xf8, 0xa6, 0x1e,
64	}
65
66	// manually sign the record and attach signature to "expected"
67	signature := ed25519.Sign(ownerOne.privateKey, expected)
68	r.Signature = signature
69	l := util.ToVarint64(uint64(len(signature)))
70	expected = append(expected, l...)
71	expected = append(expected, signature...)
72
73	// manually countersign the record and attach countersignature to "expected"
74	signature = ed25519.Sign(ownerTwo.privateKey, expected)
75	r.Countersignature = signature
76	l = util.ToVarint64(uint64(len(signature)))
77	expected = append(expected, l...)
78	expected = append(expected, signature...)
79
80	// test the packer
81	packed, err := r.Pack(ownerOneAccount)
82	if nil != err {
83		t.Errorf("pack error: %s", err)
84	}
85
86	// if either of above fail we will have the message _without_ a signature
87	if !bytes.Equal(packed, expected) {
88		t.Errorf("pack record: %x  expected: %x", packed, expected)
89		t.Errorf("*** GENERATED Packed:\n%s", util.FormatBytes("expected", packed))
90		t.Fatal("fatal error")
91	}
92
93	t.Logf("Packed length: %d bytes", len(packed))
94
95	// check txId
96	txId := packed.MakeLink()
97
98	if txId != expectedTxId {
99		t.Errorf("pack txId: %#v  expected: %x", txId, expectedTxId)
100		t.Errorf("*** GENERATED txId:\n%s", util.FormatBytes("expectedTxId", txId[:]))
101		t.Fatal("fatal error")
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	if len(packed) != n {
110		t.Errorf("did not unpack all data: only used: %d of: %d bytes", n, len(packed))
111	}
112
113	grant, ok := unpacked.(*transactionrecord.ShareGrant)
114	if !ok {
115		t.Fatalf("did not unpack to ShareGrant")
116	}
117
118	// display a JSON version for information
119	item := struct {
120		TxId       merkle.Digest
121		ShareGrant *transactionrecord.ShareGrant
122	}{
123		txId,
124		grant,
125	}
126	b, err := json.MarshalIndent(item, "", "  ")
127	if nil != err {
128		t.Fatalf("json error: %s", err)
129	}
130
131	t.Logf("Share Grant: JSON: %s", b)
132
133	// check that structure is preserved through Pack/Unpack
134	// note reg is a pointer here
135	if !reflect.DeepEqual(r, *grant) {
136		t.Fatalf("different, original: %v  recovered: %v", r, *grant)
137	}
138}
139
140// test the packing/unpacking of Share grant record
141//
142// ensures that value cannot be zero
143func TestPackShareGrantValueNotZero(t *testing.T) {
144
145	ownerOneAccount := makeAccount(ownerOne.publicKey)
146	ownerTwoAccount := makeAccount(ownerTwo.publicKey)
147
148	var shareId merkle.Digest
149	err := merkleDigestFromLE("630c041cd1f586bcb9097e816189185c1e0379f67bbfc2f0626724f542047873", &shareId)
150	if nil != err {
151		t.Fatalf("hex to share error: %s", err)
152	}
153
154	r := transactionrecord.ShareGrant{
155		ShareId:   shareId,
156		Quantity:  0,
157		Owner:     ownerOneAccount,
158		Recipient: ownerTwoAccount,
159	}
160
161	expected := []byte{
162		0x09, 0x20, 0x63, 0x0c, 0x04, 0x1c, 0xd1, 0xf5,
163		0x86, 0xbc, 0xb9, 0x09, 0x7e, 0x81, 0x61, 0x89,
164		0x18, 0x5c, 0x1e, 0x03, 0x79, 0xf6, 0x7b, 0xbf,
165		0xc2, 0xf0, 0x62, 0x67, 0x24, 0xf5, 0x42, 0x04,
166		0x78, 0x73, 0x00, 0x21, 0x13, 0x27, 0x64, 0x0e,
167		0x4a, 0xab, 0x92, 0xd8, 0x7b, 0x4a, 0x6a, 0x2f,
168		0x30, 0xb8, 0x81, 0xf4, 0x49, 0x29, 0xf8, 0x66,
169		0x04, 0x3a, 0x84, 0x1c, 0x38, 0x14, 0xb1, 0x66,
170		0xb8, 0x89, 0x44, 0xb0, 0x92, 0x21, 0x13, 0xa1,
171		0x36, 0x32, 0xd5, 0x42, 0x5a, 0xed, 0x3a, 0x6b,
172		0x62, 0xe2, 0xbb, 0x6d, 0xe4, 0xc9, 0x59, 0x48,
173		0x41, 0xc1, 0x5b, 0x70, 0x15, 0x69, 0xec, 0x99,
174		0x99, 0xdc, 0x20, 0x1c, 0x35, 0xf7, 0xb3, 0x00,
175	}
176
177	// manually sign the record and attach signature to "expected"
178	signature := ed25519.Sign(ownerOne.privateKey, expected)
179	r.Signature = signature
180	l := util.ToVarint64(uint64(len(signature)))
181	expected = append(expected, l...)
182	expected = append(expected, signature...)
183
184	// manually countersign the record and attach countersignature to "expected"
185	signature = ed25519.Sign(ownerTwo.privateKey, expected)
186	r.Countersignature = signature
187
188	// test the packer
189	_, err = r.Pack(ownerOneAccount)
190	if fault.ShareQuantityTooSmall != err {
191		t.Fatalf("unexpected pack error: %s", err)
192	}
193}
194