11 "github.com/davecgh/go-spew/spew"
12 "golang.org/x/crypto/sha3"
14 "github.com/vapor/common"
15 "github.com/vapor/consensus"
16 "github.com/vapor/crypto"
17 "github.com/vapor/crypto/ed25519"
18 "github.com/vapor/crypto/ed25519/chainkd"
19 chainjson "github.com/vapor/encoding/json"
20 "github.com/vapor/errors"
21 "github.com/vapor/protocol/bc"
22 "github.com/vapor/protocol/bc/types"
23 "github.com/vapor/protocol/vm"
24 "github.com/vapor/protocol/vm/vmutil"
25 "github.com/vapor/testutil"
28 type testAction bc.AssetAmount
30 func (t testAction) Build(ctx context.Context, b *TemplateBuilder) error {
31 in := types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *t.AssetId, t.Amount, 0, nil)
32 tplIn := &SigningInstruction{}
34 err := b.AddInput(in, tplIn)
38 return b.AddOutput(types.NewTxOutput(*t.AssetId, t.Amount, []byte("change")))
41 func (t testAction) ActionType() string {
45 func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlProgramAction {
46 return &controlProgramAction{
47 AssetAmount: assetAmt,
52 func TestBuild(t *testing.T) {
53 ctx := context.Background()
55 assetID1 := bc.NewAssetID([32]byte{1})
56 assetID2 := bc.NewAssetID([32]byte{2})
59 newControlProgramAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, []byte("dest")),
60 testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}),
62 expiryTime := time.Now().Add(time.Minute)
63 got, err := Build(ctx, nil, actions, expiryTime, 0)
65 testutil.FatalErr(t, err)
69 Transaction: types.NewTx(types.TxData{
71 Inputs: []*types.TxInput{
72 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), assetID1, 5, 0, nil),
74 Outputs: []*types.TxOutput{
75 types.NewTxOutput(assetID2, 6, []byte("dest")),
76 types.NewTxOutput(assetID1, 5, []byte("change")),
79 SigningInstructions: []*SigningInstruction{{
80 WitnessComponents: []witnessComponent{},
84 if !testutil.DeepEqual(got.Transaction.TxData, want.Transaction.TxData) {
85 t.Errorf("got tx:\n%s\nwant tx:\n%s", spew.Sdump(got.Transaction.TxData), spew.Sdump(want.Transaction.TxData))
88 if !testutil.DeepEqual(got.SigningInstructions, want.SigningInstructions) {
89 t.Errorf("got signing instructions:\n\t%#v\nwant signing instructions:\n\t%#v", got.SigningInstructions, want.SigningInstructions)
93 func TestSignatureWitnessMaterialize(t *testing.T) {
94 privkey1, pubkey1, err := chainkd.NewXKeys(nil)
98 privkey2, pubkey2, err := chainkd.NewXKeys(nil)
102 privkey3, pubkey3, err := chainkd.NewXKeys(nil)
106 issuanceProg, _ := vmutil.P2SPMultiSigProgram([]ed25519.PublicKey{pubkey1.PublicKey(), pubkey2.PublicKey(), pubkey3.PublicKey()}, 2)
107 assetID := bc.ComputeAssetID(issuanceProg, 1, &bc.EmptyStringHash)
108 outscript := mustDecodeHex("76a914c5d128911c28776f56baaac550963f7b88501dc388c0")
109 unsigned := types.NewTx(types.TxData{
111 Inputs: []*types.TxInput{
112 types.NewIssuanceInput([]byte{1}, 100, issuanceProg, nil, nil),
114 Outputs: []*types.TxOutput{
115 types.NewTxOutput(assetID, 100, outscript),
120 Transaction: unsigned,
123 builder := vmutil.NewBuilder()
124 builder.AddData(h.Bytes())
125 builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL)
126 prog, _ := builder.Build()
127 msg := sha3.Sum256(prog)
128 sig1 := privkey1.Sign(msg[:])
129 sig2 := privkey2.Sign(msg[:])
130 sig3 := privkey3.Sign(msg[:])
138 // Test with more signatures than required, in correct order
139 tpl.SigningInstructions = []*SigningInstruction{{
140 WitnessComponents: []witnessComponent{
146 DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
150 DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
154 DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
158 Sigs: []chainjson.HexBytes{sig1, sig2, sig3},
162 err = materializeWitnesses(tpl)
164 testutil.FatalErr(t, err)
166 got := tpl.Transaction.Inputs[0].Arguments()
167 if !testutil.DeepEqual(got, want) {
168 t.Errorf("got input witness %v, want input witness %v", got, want)
171 // Test with exact amount of signatures required, in correct order
172 component := tpl.SigningInstructions[0].WitnessComponents[0].(*SignatureWitness)
173 component.Sigs = []chainjson.HexBytes{sig1, sig2}
174 err = materializeWitnesses(tpl)
176 testutil.FatalErr(t, err)
178 got = tpl.Transaction.Inputs[0].Arguments()
179 if !testutil.DeepEqual(got, want) {
180 t.Errorf("got input witness %v, want input witness %v", got, want)
184 func mustDecodeHex(str string) []byte {
185 data, err := hex.DecodeString(str)
192 func TestCheckBlankCheck(t *testing.T) {
198 Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
203 Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
204 Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 3, nil)},
209 Inputs: []*types.TxInput{
210 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
211 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.NewAssetID([32]byte{1}), 5, 0, nil),
213 Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
218 Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
219 Outputs: []*types.TxOutput{
220 types.NewTxOutput(bc.AssetID{}, math.MaxInt64, nil),
221 types.NewTxOutput(bc.AssetID{}, 7, nil),
227 Inputs: []*types.TxInput{
228 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
229 types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, math.MaxInt64, 0, nil),
235 Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
236 Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
241 Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
246 Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
247 Outputs: []*types.TxOutput{types.NewTxOutput(bc.NewAssetID([32]byte{1}), 5, nil)},
252 for _, c := range cases {
253 got := checkBlankCheck(c.tx)
254 if errors.Root(got) != c.want {
255 t.Errorf("checkUnsafe(%+v) err = %v want %v", c.tx, errors.Root(got), c.want)
260 func TestCreateTxByUtxo(t *testing.T) {
261 xprv, xpub, err := chainkd.NewXKeys(nil)
266 pub := xpub.PublicKey()
267 pubHash := crypto.Ripemd160(pub)
268 program, err := vmutil.P2WPKHProgram([]byte(pubHash))
273 address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
278 muxID := testutil.MustDecodeHash("1e673900965623ec3305cead5a78dfb68a34599f8bc078460f3f202256c3dfa6")
284 ControlProgram []byte
288 AssetID: *consensus.BTMAssetID,
291 ControlProgram: program,
292 Address: address.EncodeAddress(),
295 recvProg := mustDecodeHex("00145056532ecd3621c9ce8adde5505c058610b287cf")
296 tx := types.NewTx(types.TxData{
298 Inputs: []*types.TxInput{
299 types.NewSpendInput(nil, utxo.SourceID, utxo.AssetID, utxo.Amount, utxo.SourcePos, utxo.ControlProgram),
301 Outputs: []*types.TxOutput{
302 types.NewTxOutput(*consensus.BTMAssetID, 10000000000, recvProg),
308 AllowAdditional: false,
311 h := tpl.Hash(0).Byte32()
312 sig := xprv.Sign(h[:])
315 // Test with more signatures than required, in correct order
316 tpl.SigningInstructions = []*SigningInstruction{{
317 WitnessComponents: []witnessComponent{
320 Sigs: []chainjson.HexBytes{sig},
326 if err = materializeWitnesses(tpl); err != nil {
330 if !testutil.DeepEqual(tx, tpl.Transaction) {
331 t.Errorf("tx:%v result is equal to want:%v", tx, tpl.Transaction)
335 func TestAddContractArgs(t *testing.T) {
336 hexXpub, err := hex.DecodeString("ba76bb52574b3f40315f2c01f1818a9072ced56e9d4b68acbef56a4d0077d08e5e34837963e4cdc54eb251aa34aad01e6ae48b140f6a2743fbb0a0abd9cf8aac")
341 var xpub chainkd.XPub
342 copy(xpub[:], hexXpub)
344 rawTxSig := RawTxSigArgument{RootXPub: xpub, Path: []chainjson.HexBytes{{1, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0}}}
345 rawTxSigMsg, err := json.Marshal(rawTxSig)
350 value, err := hex.DecodeString("7468697320697320612074657374")
354 data := DataArgument{value}
355 dataMsg, err := json.Marshal(data)
360 strMsg, err := json.Marshal(StrArgument{"this is a test string"})
365 integerMsg, err := json.Marshal(IntegerArgument{100})
370 boolMsg, err := json.Marshal(BoolArgument{true})
376 arguments []ContractArgument
380 arguments: []ContractArgument{
382 Type: "raw_tx_signature",
383 RawData: rawTxSigMsg,
389 arguments: []ContractArgument{
398 arguments: []ContractArgument{
407 arguments: []ContractArgument{
416 arguments: []ContractArgument{
425 arguments: []ContractArgument{
427 Type: "raw_tx_signature",
428 RawData: rawTxSigMsg,
438 arguments: []ContractArgument{
444 Type: "raw_tx_signature",
445 RawData: rawTxSigMsg,
451 arguments: []ContractArgument{
453 Type: "raw_tx_signature",
454 RawData: rawTxSigMsg,
476 arguments: []ContractArgument{
483 RawData: rawTxSigMsg,
486 wantResult: ErrBadContractArgType,
490 sigInst := &SigningInstruction{}
491 for _, c := range cases {
492 err := AddContractArgs(sigInst, c.arguments)
493 if err != c.wantResult {
494 t.Fatalf("got result=%v, want result=%v", err, c.wantResult)