OSDN Git Service

feat: build cross-out tx (#74)
authorHAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
Mon, 20 May 2019 12:16:50 +0000 (20:16 +0800)
committerPaladz <yzhu101@uottawa.ca>
Mon, 20 May 2019 12:16:50 +0000 (20:16 +0800)
* 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

api/transact.go
blockchain/txbuilder/actions.go
blockchain/txbuilder/txbuilder_test.go
config/config.go

index 25d61bc..4a6c17c 100644 (file)
@@ -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,
        }
index 185be8e..8da65a7 100644 (file)
@@ -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"
+}
index 2fcd6a6..8cd1432 100644 (file)
@@ -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 {
index 03d7d6f..69b4882 100644 (file)
@@ -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")
        }
 }