+++ /dev/null
-package txbuilder
-
-import (
- "context"
- "encoding/hex"
- "encoding/json"
- "math"
- "testing"
- "time"
-
- "github.com/davecgh/go-spew/spew"
- "golang.org/x/crypto/sha3"
-
- "github.com/vapor/common"
- "github.com/vapor/consensus"
- "github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519"
- "github.com/vapor/crypto/ed25519/chainkd"
- chainjson "github.com/vapor/encoding/json"
- "github.com/vapor/errors"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
- "github.com/vapor/protocol/vm"
- "github.com/vapor/protocol/vm/vmutil"
- "github.com/vapor/testutil"
-)
-
-type testAction bc.AssetAmount
-
-func (t testAction) Build(ctx context.Context, b *TemplateBuilder) error {
- in := types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *t.AssetId, t.Amount, 0, nil)
- tplIn := &SigningInstruction{}
-
- err := b.AddInput(in, tplIn)
- if err != nil {
- return err
- }
- return b.AddOutput(types.NewTxOutput(*t.AssetId, t.Amount, []byte("change")))
-}
-
-func (t testAction) ActionType() string {
- return "test-action"
-}
-
-func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlProgramAction {
- return &controlProgramAction{
- AssetAmount: assetAmt,
- Program: script,
- }
-}
-
-func TestBuild(t *testing.T) {
- ctx := context.Background()
-
- assetID1 := bc.NewAssetID([32]byte{1})
- assetID2 := bc.NewAssetID([32]byte{2})
-
- actions := []Action{
- newControlProgramAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, []byte("dest")),
- testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}),
- }
- expiryTime := time.Now().Add(time.Minute)
- got, err := Build(ctx, nil, actions, expiryTime, 0)
- if err != nil {
- testutil.FatalErr(t, err)
- }
-
- want := &Template{
- Transaction: types.NewTx(types.TxData{
- Version: 1,
- Inputs: []*types.TxInput{
- types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), assetID1, 5, 0, nil),
- },
- Outputs: []*types.TxOutput{
- types.NewTxOutput(assetID2, 6, []byte("dest")),
- types.NewTxOutput(assetID1, 5, []byte("change")),
- },
- }),
- SigningInstructions: []*SigningInstruction{{
- WitnessComponents: []witnessComponent{},
- }},
- }
-
- if !testutil.DeepEqual(got.Transaction.TxData, want.Transaction.TxData) {
- t.Errorf("got tx:\n%s\nwant tx:\n%s", spew.Sdump(got.Transaction.TxData), spew.Sdump(want.Transaction.TxData))
- }
-
- if !testutil.DeepEqual(got.SigningInstructions, want.SigningInstructions) {
- t.Errorf("got signing instructions:\n\t%#v\nwant signing instructions:\n\t%#v", got.SigningInstructions, want.SigningInstructions)
- }
-}
-
-func TestSignatureWitnessMaterialize(t *testing.T) {
- privkey1, pubkey1, err := chainkd.NewXKeys(nil)
- if err != nil {
- t.Fatal(err)
- }
- privkey2, pubkey2, err := chainkd.NewXKeys(nil)
- if err != nil {
- t.Fatal(err)
- }
- privkey3, pubkey3, err := chainkd.NewXKeys(nil)
- if err != nil {
- t.Fatal(err)
- }
- issuanceProg, _ := vmutil.P2SPMultiSigProgram([]ed25519.PublicKey{pubkey1.PublicKey(), pubkey2.PublicKey(), pubkey3.PublicKey()}, 2)
- assetID := bc.ComputeAssetID(issuanceProg, 1, &bc.EmptyStringHash)
- outscript := mustDecodeHex("76a914c5d128911c28776f56baaac550963f7b88501dc388c0")
- unsigned := types.NewTx(types.TxData{
- Version: 1,
- Inputs: []*types.TxInput{
- types.NewIssuanceInput([]byte{1}, 100, issuanceProg, nil, nil),
- },
- Outputs: []*types.TxOutput{
- types.NewTxOutput(assetID, 100, outscript),
- },
- })
-
- tpl := &Template{
- Transaction: unsigned,
- }
- h := tpl.Hash(0)
- builder := vmutil.NewBuilder()
- builder.AddData(h.Bytes())
- builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL)
- prog, _ := builder.Build()
- msg := sha3.Sum256(prog)
- sig1 := privkey1.Sign(msg[:])
- sig2 := privkey2.Sign(msg[:])
- sig3 := privkey3.Sign(msg[:])
- want := [][]byte{
- vm.Int64Bytes(0),
- sig1,
- sig2,
- prog,
- }
-
- // Test with more signatures than required, in correct order
- tpl.SigningInstructions = []*SigningInstruction{{
- WitnessComponents: []witnessComponent{
- &SignatureWitness{
- Quorum: 2,
- Keys: []keyID{
- {
- XPub: pubkey1,
- DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
- },
- {
- XPub: pubkey2,
- DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
- },
- {
- XPub: pubkey3,
- DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}},
- },
- },
- Program: prog,
- Sigs: []chainjson.HexBytes{sig1, sig2, sig3},
- },
- },
- }}
- err = materializeWitnesses(tpl)
- if err != nil {
- testutil.FatalErr(t, err)
- }
- got := tpl.Transaction.Inputs[0].Arguments()
- if !testutil.DeepEqual(got, want) {
- t.Errorf("got input witness %v, want input witness %v", got, want)
- }
-
- // Test with exact amount of signatures required, in correct order
- component := tpl.SigningInstructions[0].WitnessComponents[0].(*SignatureWitness)
- component.Sigs = []chainjson.HexBytes{sig1, sig2}
- err = materializeWitnesses(tpl)
- if err != nil {
- testutil.FatalErr(t, err)
- }
- got = tpl.Transaction.Inputs[0].Arguments()
- if !testutil.DeepEqual(got, want) {
- t.Errorf("got input witness %v, want input witness %v", got, want)
- }
-}
-
-func mustDecodeHex(str string) []byte {
- data, err := hex.DecodeString(str)
- if err != nil {
- panic(err)
- }
- return data
-}
-
-func TestCheckBlankCheck(t *testing.T) {
- cases := []struct {
- tx *types.TxData
- want error
- }{{
- tx: &types.TxData{
- Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
- },
- want: ErrBlankCheck,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
- Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 3, nil)},
- },
- want: ErrBlankCheck,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{
- types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
- types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.NewAssetID([32]byte{1}), 5, 0, nil),
- },
- Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
- },
- want: ErrBlankCheck,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
- Outputs: []*types.TxOutput{
- types.NewTxOutput(bc.AssetID{}, math.MaxInt64, nil),
- types.NewTxOutput(bc.AssetID{}, 7, nil),
- },
- },
- want: ErrBadAmount,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{
- types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil),
- types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, math.MaxInt64, 0, nil),
- },
- },
- want: ErrBadAmount,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
- Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
- },
- want: nil,
- }, {
- tx: &types.TxData{
- Outputs: []*types.TxOutput{types.NewTxOutput(bc.AssetID{}, 5, nil)},
- },
- want: nil,
- }, {
- tx: &types.TxData{
- Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), bc.AssetID{}, 5, 0, nil)},
- Outputs: []*types.TxOutput{types.NewTxOutput(bc.NewAssetID([32]byte{1}), 5, nil)},
- },
- want: nil,
- }}
-
- for _, c := range cases {
- got := checkBlankCheck(c.tx)
- if errors.Root(got) != c.want {
- t.Errorf("checkUnsafe(%+v) err = %v want %v", c.tx, errors.Root(got), c.want)
- }
- }
-}
-
-func TestCreateTxByUtxo(t *testing.T) {
- xprv, xpub, err := chainkd.NewXKeys(nil)
- if err != nil {
- t.Fatal(err)
- }
-
- pub := xpub.PublicKey()
- pubHash := crypto.Ripemd160(pub)
- program, err := vmutil.P2WPKHProgram([]byte(pubHash))
- if err != nil {
- t.Fatal(err)
- }
-
- address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
- if err != nil {
- t.Fatal(err)
- }
-
- muxID := testutil.MustDecodeHash("1e673900965623ec3305cead5a78dfb68a34599f8bc078460f3f202256c3dfa6")
- utxo := struct {
- SourceID bc.Hash
- AssetID bc.AssetID
- Amount uint64
- SourcePos uint64
- ControlProgram []byte
- Address string
- }{
- SourceID: muxID,
- AssetID: *consensus.BTMAssetID,
- Amount: 20000000000,
- SourcePos: 1,
- ControlProgram: program,
- Address: address.EncodeAddress(),
- }
-
- recvProg := mustDecodeHex("00145056532ecd3621c9ce8adde5505c058610b287cf")
- tx := types.NewTx(types.TxData{
- Version: 1,
- Inputs: []*types.TxInput{
- types.NewSpendInput(nil, utxo.SourceID, utxo.AssetID, utxo.Amount, utxo.SourcePos, utxo.ControlProgram),
- },
- Outputs: []*types.TxOutput{
- types.NewTxOutput(*consensus.BTMAssetID, 10000000000, recvProg),
- },
- })
-
- tpl := &Template{
- Transaction: tx,
- AllowAdditional: false,
- }
-
- h := tpl.Hash(0).Byte32()
- sig := xprv.Sign(h[:])
- data := []byte(pub)
-
- // Test with more signatures than required, in correct order
- tpl.SigningInstructions = []*SigningInstruction{{
- WitnessComponents: []witnessComponent{
- &RawTxSigWitness{
- Quorum: 1,
- Sigs: []chainjson.HexBytes{sig},
- },
- DataWitness(data),
- },
- }}
-
- if err = materializeWitnesses(tpl); err != nil {
- t.Fatal(err)
- }
-
- if !testutil.DeepEqual(tx, tpl.Transaction) {
- t.Errorf("tx:%v result is equal to want:%v", tx, tpl.Transaction)
- }
-}
-
-func TestAddContractArgs(t *testing.T) {
- hexXpub, err := hex.DecodeString("ba76bb52574b3f40315f2c01f1818a9072ced56e9d4b68acbef56a4d0077d08e5e34837963e4cdc54eb251aa34aad01e6ae48b140f6a2743fbb0a0abd9cf8aac")
- if err != nil {
- t.Fatal(err)
- }
-
- var xpub chainkd.XPub
- copy(xpub[:], hexXpub)
-
- rawTxSig := RawTxSigArgument{RootXPub: xpub, Path: []chainjson.HexBytes{{1, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0}}}
- rawTxSigMsg, err := json.Marshal(rawTxSig)
- if err != nil {
- t.Fatal(err)
- }
-
- value, err := hex.DecodeString("7468697320697320612074657374")
- if err != nil {
- t.Fatal(err)
- }
- data := DataArgument{value}
- dataMsg, err := json.Marshal(data)
- if err != nil {
- t.Fatal(err)
- }
-
- strMsg, err := json.Marshal(StrArgument{"this is a test string"})
- if err != nil {
- t.Fatal(err)
- }
-
- integerMsg, err := json.Marshal(IntegerArgument{100})
- if err != nil {
- t.Fatal(err)
- }
-
- boolMsg, err := json.Marshal(BoolArgument{true})
- if err != nil {
- t.Fatal(err)
- }
-
- cases := []struct {
- arguments []ContractArgument
- wantResult error
- }{
- {
- arguments: []ContractArgument{
- {
- Type: "raw_tx_signature",
- RawData: rawTxSigMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "data",
- RawData: dataMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "string",
- RawData: strMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "integer",
- RawData: integerMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "boolean",
- RawData: boolMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "raw_tx_signature",
- RawData: rawTxSigMsg,
- },
- {
- Type: "data",
- RawData: dataMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "data",
- RawData: dataMsg,
- },
- {
- Type: "raw_tx_signature",
- RawData: rawTxSigMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "raw_tx_signature",
- RawData: rawTxSigMsg,
- },
- {
- Type: "data",
- RawData: dataMsg,
- },
- {
- Type: "string",
- RawData: strMsg,
- },
- {
- Type: "integer",
- RawData: integerMsg,
- },
- {
- Type: "boolean",
- RawData: boolMsg,
- },
- },
- wantResult: nil,
- },
- {
- arguments: []ContractArgument{
- {
- Type: "data",
- RawData: dataMsg,
- },
- {
- Type: "err_data",
- RawData: rawTxSigMsg,
- },
- },
- wantResult: ErrBadContractArgType,
- },
- }
-
- sigInst := &SigningInstruction{}
- for _, c := range cases {
- err := AddContractArgs(sigInst, c.arguments)
- if err != c.wantResult {
- t.Fatalf("got result=%v, want result=%v", err, c.wantResult)
- }
- }
-}