From: oysheng Date: Mon, 16 Apr 2018 08:40:55 +0000 (+0800) Subject: add api calculate-transaction-gas X-Git-Tag: v1.0.5~130^2~3 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=66988dcd930193b7905207dce3b567e2984d213d;p=bytom%2Fbytom.git add api calculate-transaction-gas --- diff --git a/api/api.go b/api/api.go index f43620e4..0ccaad33 100644 --- a/api/api.go +++ b/api/api.go @@ -191,6 +191,7 @@ func (a *API) buildHandler() { m.Handle("/build-transaction", jsonHandler(a.build)) m.Handle("/sign-transaction", jsonHandler(a.pseudohsmSignTemplates)) m.Handle("/submit-transaction", jsonHandler(a.submit)) + m.Handle("/calculate-transaction-gas", jsonHandler(a.calculateGas)) // TODO remove this api, separate sign and submit process m.Handle("/sign-submit-transaction", jsonHandler(a.signSubmit)) m.Handle("/get-transaction", jsonHandler(a.getTransaction)) diff --git a/api/transact.go b/api/transact.go index 4a72dd4d..c1b1ff87 100644 --- a/api/transact.go +++ b/api/transact.go @@ -11,7 +11,9 @@ import ( "github.com/bytom/blockchain/pseudohsm" "github.com/bytom/blockchain/txbuilder" + "github.com/bytom/consensus" "github.com/bytom/errors" + "github.com/bytom/math/checked" "github.com/bytom/net/http/reqid" "github.com/bytom/protocol/bc" "github.com/bytom/protocol/bc/types" @@ -43,7 +45,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro } func mergeActions(req *BuildRequest) []map[string]interface{} { - actions := make([]map[string]interface{}, 0) + var actions []map[string]interface{} actionMap := make(map[string]map[string]interface{}) for _, m := range req.Actions { @@ -205,3 +207,38 @@ func (a *API) signSubmit(ctx context.Context, x struct { log.WithField("tx_id", txID["tx_id"]).Info("submit single tx") return NewSuccessResponse(txID) } + +type calculateTxGasResp struct { + LeftBTM int64 `json:"left_btm"` + ConsumedBTM int64 `json:"consumed_btm"` + LeftGas int64 `json:"left_gas"` + ConsumedGas int64 `json:"consumed_gas"` + StorageGas int64 `json:"storage_gas"` + VMGas int64 `json:"vm_gas"` +} + +// POST /calculate-transaction-gas +func (a *API) calculateGas(ctx context.Context, ins struct { + Tx types.Tx `json:"raw_transaction"` +}) Response { + gasState, err := txbuilder.CalculateTxGas(a.chain, &ins.Tx) + if err != nil { + return NewErrorResponse(err) + } + + btmLeft, ok := checked.MulInt64(gasState.GasLeft, consensus.VMGasRate) + if !ok { + return NewErrorResponse(errors.New("calculate btmleft got a math error")) + } + + txGasResp := &calculateTxGasResp{ + LeftBTM: btmLeft, + ConsumedBTM: int64(gasState.BTMValue) - btmLeft, + LeftGas: gasState.GasLeft, + ConsumedGas: gasState.GasUsed, + StorageGas: gasState.StorageGas, + VMGas: gasState.GasUsed - gasState.StorageGas, + } + + return NewSuccessResponse(txGasResp) +} diff --git a/blockchain/txbuilder/finalize.go b/blockchain/txbuilder/finalize.go index 043954e2..edb6fc05 100644 --- a/blockchain/txbuilder/finalize.go +++ b/blockchain/txbuilder/finalize.go @@ -7,6 +7,7 @@ import ( "github.com/bytom/errors" "github.com/bytom/protocol" "github.com/bytom/protocol/bc/types" + "github.com/bytom/protocol/validation" "github.com/bytom/protocol/vm" ) @@ -46,6 +47,27 @@ func FinalizeTx(ctx context.Context, c *protocol.Chain, tx *types.Tx) error { return errors.Wrap(err) } +// CalculateTxGas calculate a transaction gas by validating a transaction +func CalculateTxGas(c *protocol.Chain, tx *types.Tx) (*validation.GasState, error) { + // This part is use for prevent tx size is 0 + data, err := tx.TxData.MarshalText() + if err != nil { + return nil, err + } + tx.TxData.SerializedSize = uint64(len(data)) + tx.Tx.SerializedSize = uint64(len(data)) + + bh := c.BestBlockHeader() + block := types.MapBlock(&types.Block{BlockHeader: *bh}) + + gasState, err := validation.ValidateTx(tx.Tx, block) + if err != nil { + return nil, err + } + + return gasState, nil +} + var ( // ErrNoTxSighashCommitment is returned when no input commits to the // complete transaction. diff --git a/cmd/bytomcli/commands/bytomcli.go b/cmd/bytomcli/commands/bytomcli.go index e3584c0c..b3b1582c 100644 --- a/cmd/bytomcli/commands/bytomcli.go +++ b/cmd/bytomcli/commands/bytomcli.go @@ -97,6 +97,7 @@ func AddCommands() { BytomcliCmd.AddCommand(buildTransactionCmd) BytomcliCmd.AddCommand(signTransactionCmd) BytomcliCmd.AddCommand(submitTransactionCmd) + BytomcliCmd.AddCommand(calculateTransactionGasCmd) BytomcliCmd.AddCommand(signSubTransactionCmd) BytomcliCmd.AddCommand(getBlockCountCmd) diff --git a/cmd/bytomcli/commands/transaction.go b/cmd/bytomcli/commands/transaction.go index ac738a61..69fb5edd 100644 --- a/cmd/bytomcli/commands/transaction.go +++ b/cmd/bytomcli/commands/transaction.go @@ -227,7 +227,7 @@ var signTransactionCmd = &cobra.Command{ var submitTransactionCmd = &cobra.Command{ Use: "submit-transaction ", - Short: "Submit signed transaction template", + Short: "Submit signed transaction", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { var ins = struct { @@ -249,6 +249,30 @@ var submitTransactionCmd = &cobra.Command{ }, } +var calculateTransactionGasCmd = &cobra.Command{ + Use: "calculate-transaction-gas ", + Short: "calculate gas for signed transaction", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + var ins = struct { + Tx types.Tx `json:"raw_transaction"` + }{} + + err := json.Unmarshal([]byte(args[0]), &ins) + if err != nil { + jww.ERROR.Println(err) + os.Exit(util.ErrLocalExe) + } + + data, exitCode := util.ClientCall("/calculate-transaction-gas", &ins) + if exitCode != util.Success { + os.Exit(exitCode) + } + + printJSON(data) + }, +} + var signSubTransactionCmd = &cobra.Command{ Use: "sign-submit-transaction ", Short: "Sign and Submit transaction templates with account password", @@ -266,7 +290,7 @@ var signSubTransactionCmd = &cobra.Command{ } var req = struct { - Password string `json:"password"` + Password string `json:"password"` Txs txbuilder.Template `json:"transaction"` }{Password: password, Txs: template}