OSDN Git Service

Merger utxo (#383)
authorwz <mars@bytom.io>
Tue, 13 Aug 2019 07:25:31 +0000 (15:25 +0800)
committerPaladz <yzhu101@uottawa.ca>
Tue, 13 Aug 2019 07:25:31 +0000 (15:25 +0800)
* add merger utxo

* add chain tx

* delete code

* Function implementation

* modify param

* modify readme

* fix review and fix tet

* fix test

README.md
account/builder.go
cmd/utxomerge/README.md [new file with mode: 0644]
cmd/utxomerge/main.go [new file with mode: 0644]
test/builder_test.go
toolbar/apinode/transaction.go
toolbar/mergeutxo/merger_utxo.go [new file with mode: 0755]

index 52870ed..e8e838e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -121,6 +121,11 @@ cast in consensus around, and choose how many rounds of consensus to allocate th
 
 [Tool usage details](./cmd/votereward/README.md)
 
 
 [Tool usage details](./cmd/votereward/README.md)
 
+
+### Merger utxo
+UTXO has been merged to solve the problem that too much UTXO input causes a failed send transaction to fail. 
+[details](./toolbar/merger_utxo/README.md)
+
 ## License
 
 [AGPL v3](./LICENSE)
 ## License
 
 [AGPL v3](./LICENSE)
index 143ad24..ca533a0 100644 (file)
@@ -18,7 +18,7 @@ import (
 
 var (
        //chainTxUtxoNum maximum utxo quantity in a tx
 
 var (
        //chainTxUtxoNum maximum utxo quantity in a tx
-       chainTxUtxoNum = 5
+       chainTxUtxoNum = 20
        //chainTxMergeGas chain tx gas
        chainTxMergeGas = uint64(10000000)
 )
        //chainTxMergeGas chain tx gas
        chainTxMergeGas = uint64(10000000)
 )
diff --git a/cmd/utxomerge/README.md b/cmd/utxomerge/README.md
new file mode 100644 (file)
index 0000000..1ee0a3d
--- /dev/null
@@ -0,0 +1,24 @@
+tool use
+
+params
+
+```shell
+merge utxo.
+
+Usage:
+  utxomerge [flags]
+
+Flags:
+      --account_id string   The accountID of utxo needs to be merged
+      --address string      The received address after merging utxo
+      --amount uint         Total amount of merged utxo
+  -h, --help                help for utxomerge
+      --host_port string    The url for the node. Default:http://127.0.0.1:9889 (default "http://127.0.0.1:9889")
+      --password string     Password of the account
+```
+
+example:
+
+```shell
+./utxomerge --host_port http://127.0.0.1:9889 --account_id 9e54300d-f81d-4c5f-bef3-4e771042d394 --password 123456 --address sp1q8u7xu3e389awrnct0x4flx0h3v7mrfnmpu858p --amount 200000000000
+```
\ No newline at end of file
diff --git a/cmd/utxomerge/main.go b/cmd/utxomerge/main.go
new file mode 100644 (file)
index 0000000..326595f
--- /dev/null
@@ -0,0 +1,45 @@
+package main
+
+import (
+       log "github.com/sirupsen/logrus"
+       "github.com/spf13/cobra"
+       "github.com/tendermint/tmlibs/cli"
+
+       "github.com/vapor/toolbar/mergeutxo"
+)
+
+var RootCmd = &cobra.Command{
+       Use:   "utxomerge",
+       Short: "merge utxo.",
+       RunE:  runReward,
+}
+
+var (
+       hostPort, accountID, password, address string
+       amount                                 uint64
+)
+
+func init() {
+       RootCmd.Flags().StringVar(&hostPort, "host_port", "http://127.0.0.1:9889", "The url for the node. Default:http://127.0.0.1:9889")
+       RootCmd.Flags().StringVar(&accountID, "account_id", "", "The accountID of utxo needs to be merged")
+       RootCmd.Flags().StringVar(&password, "password", "", "Password of the account")
+       RootCmd.Flags().StringVar(&address, "address", "", "The received address after merging utxo")
+       RootCmd.Flags().Uint64Var(&amount, "amount", 0, "Total amount of merged utxo")
+}
+
+func runReward(cmd *cobra.Command, args []string) error {
+       log.Info("This tool belongs to an open-source project, we can not guarantee this tool is bug-free. Please check the code before using, developers will not be responsible for any asset loss due to bug!")
+       txIDs, err := mergeutxo.MergeUTXO(hostPort, accountID, password, address, amount)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       log.Info("Merge utxo successfully. txID: ", txIDs)
+
+       return nil
+}
+
+func main() {
+       cmd := cli.PrepareBaseCmd(RootCmd, "merge_utxo", "./")
+       cmd.Execute()
+}
index 4328dbc..839a4a9 100644 (file)
@@ -55,26 +55,16 @@ func TestBuildBtmTxChain(t *testing.T) {
                        wantUtxo: 10 * chainTxMergeGas,
                },
                {
                        wantUtxo: 10 * chainTxMergeGas,
                },
                {
-                       inputUtxo: []uint64{22, 123, 53, 234, 23, 4, 2423, 24, 23, 43, 34, 234, 234, 24},
+                       inputUtxo: []uint64{22, 123, 53, 234, 23, 4, 2423, 24, 23, 43, 34, 234, 234, 24, 11, 16, 33, 59, 73, 89, 66},
                        wantInput: [][]uint64{
                        wantInput: [][]uint64{
-                               []uint64{22, 123, 53, 234, 23},
-                               []uint64{4, 2423, 24, 23, 43},
-                               []uint64{34, 234, 234, 24, 454},
-                               []uint64{2516, 979},
-                               []uint64{234, 24, 197},
-                               []uint64{260, 2469, 310},
-                               []uint64{454, 3038},
+                               []uint64{22, 123, 53, 234, 23, 4, 2423, 24, 23, 43, 34, 234, 234, 24, 11, 16, 33, 59, 73, 89},
+                               []uint64{66, 3778},
                        },
                        wantOutput: [][]uint64{
                        },
                        wantOutput: [][]uint64{
-                               []uint64{454},
-                               []uint64{2516},
-                               []uint64{979},
-                               []uint64{3494},
-                               []uint64{454},
-                               []uint64{3038},
-                               []uint64{3491},
+                               []uint64{3778},
+                               []uint64{3843},
                        },
                        },
-                       wantUtxo: 3494 * chainTxMergeGas,
+                       wantUtxo: 3843 * chainTxMergeGas,
                },
        }
 
                },
        }
 
index 682b6ed..4e9c242 100644 (file)
@@ -113,6 +113,18 @@ func (n *Node) buildTx(actions []interface{}) (*txbuilder.Template, error) {
        return result, n.request(url, payload, result)
 }
 
        return result, n.request(url, payload, result)
 }
 
+func (n *Node) BuildChainTxs(actions []interface{}) ([]*txbuilder.Template, error) {
+       url := "/build-chain-transactions"
+
+       payload, err := json.Marshal(&buildTxReq{Actions: actions})
+       if err != nil {
+               return nil, errors.Wrap(err, "Marshal spend request")
+       }
+
+       result := []*txbuilder.Template{}
+       return result, n.request(url, payload, &result)
+}
+
 type signTxReq struct {
        Tx       *txbuilder.Template `json:"transaction"`
        Password string              `json:"password"`
 type signTxReq struct {
        Tx       *txbuilder.Template `json:"transaction"`
        Password string              `json:"password"`
@@ -142,6 +154,35 @@ func (n *Node) signTx(tpl *txbuilder.Template, password string) (*txbuilder.Temp
        return resp.Tx, nil
 }
 
        return resp.Tx, nil
 }
 
+type signTxsReq struct {
+       Txs      []*txbuilder.Template `json:"transactions"`
+       Password string                `json:"password"`
+}
+
+type signTxsResp struct {
+       Txs          []*txbuilder.Template `json:"transaction"`
+       SignComplete bool                  `json:"sign_complete"`
+}
+
+func (n *Node) SignTxs(tpls []*txbuilder.Template, password string) ([]*txbuilder.Template, error) {
+       url := "/sign-transactions"
+       payload, err := json.Marshal(&signTxsReq{Txs: tpls, Password: password})
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       resp := &signTxsResp{}
+       if err := n.request(url, payload, resp); err != nil {
+               return nil, err
+       }
+
+       if !resp.SignComplete {
+               return nil, errors.New("sign fail")
+       }
+
+       return resp.Txs, nil
+}
+
 type submitTxReq struct {
        Tx *types.Tx `json:"raw_transaction"`
 }
 type submitTxReq struct {
        Tx *types.Tx `json:"raw_transaction"`
 }
@@ -160,3 +201,22 @@ func (n *Node) SubmitTx(tx *types.Tx) (string, error) {
        res := &submitTxResp{}
        return res.TxID, n.request(url, payload, res)
 }
        res := &submitTxResp{}
        return res.TxID, n.request(url, payload, res)
 }
+
+type submitTxsReq struct {
+       Txs []*types.Tx `json:"raw_transactions"`
+}
+
+type submitTxsResp struct {
+       TxsID []string `json:"tx_id"`
+}
+
+func (n *Node) SubmitTxs(txs []*types.Tx) ([]string, error) {
+       url := "/submit-transactions"
+       payload, err := json.Marshal(submitTxsReq{Txs: txs})
+       if err != nil {
+               return []string{}, errors.Wrap(err, "json marshal")
+       }
+
+       res := &submitTxsResp{}
+       return res.TxsID, n.request(url, payload, res)
+}
diff --git a/toolbar/mergeutxo/merger_utxo.go b/toolbar/mergeutxo/merger_utxo.go
new file mode 100755 (executable)
index 0000000..d8ca307
--- /dev/null
@@ -0,0 +1,41 @@
+package mergeutxo
+
+import (
+       "github.com/vapor/consensus"
+       "github.com/vapor/protocol/bc"
+       "github.com/vapor/protocol/bc/types"
+       "github.com/vapor/toolbar/apinode"
+)
+
+func MergeUTXO(hostPort, accountID, password, address string, amount uint64) ([]string, error) {
+       actions := []interface{}{}
+
+       actions = append(actions, &apinode.ControlAddressAction{
+               Address:     address,
+               AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: amount},
+       })
+
+       actions = append(actions, &apinode.SpendAccountAction{
+               AccountID:   accountID,
+               AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: amount},
+       })
+
+       node := apinode.NewNode(hostPort)
+
+       tpls, err := node.BuildChainTxs(actions)
+       if err != nil {
+               return []string{}, err
+       }
+
+       tpls, err = node.SignTxs(tpls, password)
+       if err != nil {
+               return []string{}, err
+       }
+
+       txs := []*types.Tx{}
+       for _, tpl := range tpls {
+               txs = append(txs, tpl.Transaction)
+       }
+
+       return node.SubmitTxs(txs)
+}