[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)
var (
//chainTxUtxoNum maximum utxo quantity in a tx
- chainTxUtxoNum = 5
+ chainTxUtxoNum = 20
//chainTxMergeGas chain tx gas
chainTxMergeGas = uint64(10000000)
)
--- /dev/null
+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
--- /dev/null
+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()
+}
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{
- []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{
- []uint64{454},
- []uint64{2516},
- []uint64{979},
- []uint64{3494},
- []uint64{454},
- []uint64{3038},
- []uint64{3491},
+ []uint64{3778},
+ []uint64{3843},
},
- wantUtxo: 3494 * chainTxMergeGas,
+ wantUtxo: 3843 * chainTxMergeGas,
},
}
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"`
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"`
}
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)
+}
--- /dev/null
+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)
+}