From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 20 May 2019 12:16:50 +0000 (+0800) Subject: feat: build cross-out tx (#74) X-Git-Tag: v1.0.5~208^2~110 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=322bc6bcd6f842719322930e7589963dd823615a feat: build cross-out tx (#74) * wip: init for build cross_chain_out * wip: init DecodeCrossOutAction * fix: fix crossOutAction.Build() * wip: rename test * wip: init TestBuildCrossOut * feat: add TestBuildCrossOut * refactor: rename crossOutAction.ActionType * refactor: add address instead of arbitrary in build crossOutAction * fix: fix DefaultDataDir * fix: fix TestBuildCrossOut * refactor: clean up --- diff --git a/api/transact.go b/api/transact.go index 25d61bca..4a6c17c2 100644 --- a/api/transact.go +++ b/api/transact.go @@ -26,6 +26,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro "control_address": txbuilder.DecodeControlAddressAction, "control_program": txbuilder.DecodeControlProgramAction, "retire": txbuilder.DecodeRetireAction, + "cross_chain_out": txbuilder.DecodeCrossOutAction, "spend_account": a.wallet.AccountMgr.DecodeSpendAction, "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction, } diff --git a/blockchain/txbuilder/actions.go b/blockchain/txbuilder/actions.go index 185be8e5..8da65a79 100644 --- a/blockchain/txbuilder/actions.go +++ b/blockchain/txbuilder/actions.go @@ -44,9 +44,9 @@ func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) er if err != nil { return err } + redeemContract := address.ScriptAddress() program := []byte{} - switch address.(type) { case *common.AddressWitnessPubKeyHash: program, err = vmutil.P2WPKHProgram(redeemContract) @@ -137,3 +137,57 @@ func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error { func (a *retireAction) ActionType() string { return "retire" } + +// DecodeCrossOutAction convert input data to action struct +func DecodeCrossOutAction(data []byte) (Action, error) { + a := new(crossOutAction) + err := stdjson.Unmarshal(data, a) + return a, err +} + +type crossOutAction struct { + bc.AssetAmount + Address string `json:"address"` +} + +func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error { + var missing []string + if a.Address == "" { + missing = append(missing, "address") + } + if a.AssetId.IsZero() { + missing = append(missing, "asset_id") + } + if a.Amount == 0 { + missing = append(missing, "amount") + } + if len(missing) > 0 { + return MissingFieldsError(missing...) + } + + address, err := common.DecodeAddress(a.Address, &consensus.MainNetParams) + if err != nil { + return err + } + + redeemContract := address.ScriptAddress() + program := []byte{} + switch address.(type) { + case *common.AddressWitnessPubKeyHash: + program, err = vmutil.P2WPKHProgram(redeemContract) + case *common.AddressWitnessScriptHash: + program, err = vmutil.P2WSHProgram(redeemContract) + default: + return errors.New("unsupport address type") + } + if err != nil { + return err + } + + out := types.NewCrossChainOutput(*a.AssetId, a.Amount, program) + return b.AddOutput(out) +} + +func (a *crossOutAction) ActionType() string { + return "cross_chain_out" +} diff --git a/blockchain/txbuilder/txbuilder_test.go b/blockchain/txbuilder/txbuilder_test.go index 2fcd6a6a..8cd14327 100644 --- a/blockchain/txbuilder/txbuilder_test.go +++ b/blockchain/txbuilder/txbuilder_test.go @@ -46,7 +46,7 @@ func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlPro } } -func TestBuild(t *testing.T) { +func TestBuildIntra(t *testing.T) { ctx := context.Background() assetID1 := bc.NewAssetID([32]byte{1}) @@ -87,6 +87,62 @@ func TestBuild(t *testing.T) { } } +func newCrossOutAction(assetAmt bc.AssetAmount, redeemContract []byte) *crossOutAction { + address, err := common.NewAddressWitnessPubKeyHash(redeemContract, &consensus.MainNetParams) + if err != nil { + panic(err) + } + + return &crossOutAction{ + AssetAmount: assetAmt, + Address: address.String(), + } +} + +func TestBuildCrossOut(t *testing.T) { + ctx := context.Background() + + assetID1 := bc.NewAssetID([32]byte{1}) + assetID2 := bc.NewAssetID([32]byte{2}) + + redeemContract := make([]byte, 20) + controlProgram := append([]byte{0x00, byte(len(redeemContract))}, redeemContract...) + + actions := []Action{ + newCrossOutAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, redeemContract), + 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.NewCrossChainOutput(assetID2, 6, controlProgram), + types.NewIntraChainOutput(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 mustDecodeHex(str string) []byte { data, err := hex.DecodeString(str) if err != nil { diff --git a/config/config.go b/config/config.go index 03d7d6fb..69b4882e 100644 --- a/config/config.go +++ b/config/config.go @@ -241,14 +241,14 @@ func DefaultDataDir() string { // Try to place the data folder in the user's home dir home := homeDir() if home == "" { - return "./.bytom" + return "./.vapor" } switch runtime.GOOS { case "darwin": // In order to be compatible with old data path, // copy the data from the old path to the new path - oldPath := filepath.Join(home, "Library", "Bytom") - newPath := filepath.Join(home, "Library", "Application Support", "Bytom") + oldPath := filepath.Join(home, "Library", "Vapor") + newPath := filepath.Join(home, "Library", "Application Support", "Vapor") if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) { if err := os.Rename(oldPath, newPath); err != nil { log.Errorf("DefaultDataDir: %v", err) @@ -257,9 +257,9 @@ func DefaultDataDir() string { } return newPath case "windows": - return filepath.Join(home, "AppData", "Roaming", "Bytom") + return filepath.Join(home, "AppData", "Roaming", "Vapor") default: - return filepath.Join(home, ".bytom") + return filepath.Join(home, ".vapor") } }