10 "github.com/davecgh/go-spew/spew"
12 "golang.org/x/crypto/sha3"
14 "github.com/bytom/crypto/ed25519"
15 "github.com/bytom/crypto/ed25519/chainkd"
16 "github.com/bytom/encoding/json"
17 "github.com/bytom/errors"
18 "github.com/bytom/protocol/bc"
19 "github.com/bytom/protocol/bc/legacy"
20 "github.com/bytom/protocol/vm"
21 "github.com/bytom/protocol/vm/vmutil"
22 "github.com/bytom/testutil"
25 type testAction bc.AssetAmount
27 func (t testAction) Build(ctx context.Context, b *TemplateBuilder) error {
28 in := legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *t.AssetId, t.Amount, 0, nil, bc.Hash{}, nil)
29 tplIn := &SigningInstruction{}
31 err := b.AddInput(in, tplIn)
35 return b.AddOutput(legacy.NewTxOutput(*t.AssetId, t.Amount, []byte("change"), nil))
38 func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlProgramAction {
39 return &controlProgramAction{
40 AssetAmount: assetAmt,
45 func TestBuild(t *testing.T) {
46 ctx := context.Background()
48 assetID1 := bc.NewAssetID([32]byte{1})
49 assetID2 := bc.NewAssetID([32]byte{2})
52 newControlProgramAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, []byte("dest")),
53 testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}),
54 &setTxRefDataAction{Data: []byte("xyz")},
56 expiryTime := time.Now().Add(time.Minute)
57 got, err := Build(ctx, nil, actions, expiryTime)
59 testutil.FatalErr(t, err)
63 Transaction: legacy.NewTx(legacy.TxData{
65 Inputs: []*legacy.TxInput{
66 legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), assetID1, 5, 0, nil, bc.Hash{}, nil),
68 Outputs: []*legacy.TxOutput{
69 legacy.NewTxOutput(assetID2, 6, []byte("dest"), nil),
70 legacy.NewTxOutput(assetID1, 5, []byte("change"), nil),
72 ReferenceData: []byte("xyz"),
74 SigningInstructions: []*SigningInstruction{{
75 WitnessComponents: []witnessComponent{},
79 if !testutil.DeepEqual(got.Transaction.TxData, want.Transaction.TxData) {
80 t.Errorf("got tx:\n%s\nwant tx:\n%s", spew.Sdump(got.Transaction.TxData), spew.Sdump(want.Transaction.TxData))
83 if !testutil.DeepEqual(got.SigningInstructions, want.SigningInstructions) {
84 t.Errorf("got signing instructions:\n\t%#v\nwant signing instructions:\n\t%#v", got.SigningInstructions, want.SigningInstructions)
87 // setting tx refdata twice should fail
88 actions = append(actions, &setTxRefDataAction{Data: []byte("lmnop")})
89 _, err = Build(ctx, nil, actions, expiryTime)
90 if errors.Root(err) != ErrAction {
91 t.Errorf("got error %#v, want ErrAction", err)
93 errs := errors.Data(err)["actions"].([]error)
95 t.Errorf("got error %v action errors, want 1", len(errs))
97 if errors.Root(errs[0]) != ErrBadRefData {
98 t.Errorf("got error %v in action error, want ErrBadRefData", errs[0])
102 func TestSignatureWitnessMaterialize(t *testing.T) {
103 var initialBlockHash bc.Hash
104 privkey1, pubkey1, err := chainkd.NewXKeys(nil)
108 privkey2, pubkey2, err := chainkd.NewXKeys(nil)
112 privkey3, pubkey3, err := chainkd.NewXKeys(nil)
116 issuanceProg, _ := vmutil.P2SPMultiSigProgram([]ed25519.PublicKey{pubkey1.PublicKey(), pubkey2.PublicKey(), pubkey3.PublicKey()}, 2)
117 assetID := bc.ComputeAssetID(issuanceProg, &initialBlockHash, 1, &bc.EmptyStringHash)
118 outscript := mustDecodeHex("76a914c5d128911c28776f56baaac550963f7b88501dc388c0")
119 unsigned := legacy.NewTx(legacy.TxData{
121 Inputs: []*legacy.TxInput{
122 legacy.NewIssuanceInput([]byte{1}, 100, nil, initialBlockHash, issuanceProg, nil, nil),
124 Outputs: []*legacy.TxOutput{
125 legacy.NewTxOutput(assetID, 100, outscript, nil),
130 Transaction: unsigned,
133 builder := vmutil.NewBuilder()
134 builder.AddData(h.Bytes())
135 builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL)
136 prog, _ := builder.Build()
137 msg := sha3.Sum256(prog)
138 sig1 := privkey1.Sign(msg[:])
139 sig2 := privkey2.Sign(msg[:])
140 sig3 := privkey3.Sign(msg[:])
148 // Test with more signatures than required, in correct order
149 tpl.SigningInstructions = []*SigningInstruction{{
150 WitnessComponents: []witnessComponent{
156 DerivationPath: []json.HexBytes{{0, 0, 0, 0}},
160 DerivationPath: []json.HexBytes{{0, 0, 0, 0}},
164 DerivationPath: []json.HexBytes{{0, 0, 0, 0}},
168 Sigs: []json.HexBytes{sig1, sig2, sig3},
172 err = materializeWitnesses(tpl)
174 testutil.FatalErr(t, err)
176 got := tpl.Transaction.Inputs[0].Arguments()
177 if !testutil.DeepEqual(got, want) {
178 t.Errorf("got input witness %v, want input witness %v", got, want)
181 // Test with exact amount of signatures required, in correct order
182 component := tpl.SigningInstructions[0].WitnessComponents[0].(*SignatureWitness)
183 component.Sigs = []json.HexBytes{sig1, sig2}
184 err = materializeWitnesses(tpl)
186 testutil.FatalErr(t, err)
188 got = tpl.Transaction.Inputs[0].Arguments()
189 if !testutil.DeepEqual(got, want) {
190 t.Errorf("got input witness %v, want input witness %v", got, want)
194 func mustDecodeHex(str string) []byte {
195 data, err := hex.DecodeString(str)
202 func TestCheckBlankCheck(t *testing.T) {
208 Inputs: []*legacy.TxInput{legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil)},
213 Inputs: []*legacy.TxInput{legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil)},
214 Outputs: []*legacy.TxOutput{legacy.NewTxOutput(bc.AssetID{}, 3, nil, nil)},
219 Inputs: []*legacy.TxInput{
220 legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil),
221 legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.NewAssetID([32]byte{1}), 5, 0, nil, bc.Hash{}, nil),
223 Outputs: []*legacy.TxOutput{legacy.NewTxOutput(bc.AssetID{}, 5, nil, nil)},
228 Inputs: []*legacy.TxInput{legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil)},
229 Outputs: []*legacy.TxOutput{
230 legacy.NewTxOutput(bc.AssetID{}, math.MaxInt64, nil, nil),
231 legacy.NewTxOutput(bc.AssetID{}, 7, nil, nil),
237 Inputs: []*legacy.TxInput{
238 legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil),
239 legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, math.MaxInt64, 0, nil, bc.Hash{}, nil),
245 Inputs: []*legacy.TxInput{legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil)},
246 Outputs: []*legacy.TxOutput{legacy.NewTxOutput(bc.AssetID{}, 5, nil, nil)},
251 Outputs: []*legacy.TxOutput{legacy.NewTxOutput(bc.AssetID{}, 5, nil, nil)},
256 Inputs: []*legacy.TxInput{legacy.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil, bc.Hash{}, nil)},
257 Outputs: []*legacy.TxOutput{legacy.NewTxOutput(bc.NewAssetID([32]byte{1}), 5, nil, nil)},
262 for _, c := range cases {
263 got := checkBlankCheck(c.tx)
264 if errors.Root(got) != c.want {
265 t.Errorf("checkUnsafe(%+v) err = %v want %v", c.tx, errors.Root(got), c.want)