OSDN Git Service

extract api from blockchain (#478)
[bytom/bytom.git] / blockchain / transact.go
index ae41457..4a254aa 100644 (file)
@@ -2,153 +2,14 @@ package blockchain
 
 import (
        "context"
-       "encoding/json"
-       "fmt"
-       "time"
 
        log "github.com/sirupsen/logrus"
 
        "github.com/bytom/blockchain/txbuilder"
        "github.com/bytom/errors"
-       "github.com/bytom/net/http/reqid"
-       "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
 )
 
-var defaultTxTTL = 5 * time.Minute
-
-func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, error), bool) {
-       var decoder func([]byte) (txbuilder.Action, error)
-       switch action {
-       case "control_account":
-               decoder = a.wallet.AccountMgr.DecodeControlAction
-       case "control_address":
-               decoder = txbuilder.DecodeControlAddressAction
-       case "control_program":
-               decoder = txbuilder.DecodeControlProgramAction
-       case "control_receiver":
-               decoder = txbuilder.DecodeControlReceiverAction
-       case "issue":
-               decoder = a.wallet.AssetReg.DecodeIssueAction
-       case "retire":
-               decoder = txbuilder.DecodeRetireAction
-       case "spend_account":
-               decoder = a.wallet.AccountMgr.DecodeSpendAction
-       case "spend_account_unspent_output":
-               decoder = a.wallet.AccountMgr.DecodeSpendUTXOAction
-       default:
-               return nil, false
-       }
-       return decoder, true
-}
-
-func mergeActions(req *BuildRequest) []map[string]interface{} {
-       actions := make([]map[string]interface{}, 0)
-       actionMap := make(map[string]map[string]interface{})
-
-       for _, m := range req.Actions {
-               if actionType := m["type"].(string); actionType != "spend_account" {
-                       actions = append(actions, m)
-                       continue
-               }
-
-               actionKey := m["asset_id"].(string) + m["account_id"].(string)
-               amountNumber := m["amount"].(json.Number)
-               amount, _ := amountNumber.Int64()
-
-               if tmpM, ok := actionMap[actionKey]; ok {
-                       tmpNumber, _ := tmpM["amount"].(json.Number)
-                       tmpAmount, _ := tmpNumber.Int64()
-                       tmpM["amount"] = json.Number(fmt.Sprintf("%v", tmpAmount+amount))
-               } else {
-                       actionMap[actionKey] = m
-                       actions = append(actions, m)
-               }
-       }
-
-       return actions
-}
-
-func (a *API) buildSingle(ctx context.Context, req *BuildRequest) (*txbuilder.Template, error) {
-       err := a.filterAliases(ctx, req)
-       if err != nil {
-               return nil, err
-       }
-       reqActions := mergeActions(req)
-       actions := make([]txbuilder.Action, 0, len(reqActions))
-       for i, act := range reqActions {
-               typ, ok := act["type"].(string)
-               if !ok {
-                       return nil, errors.WithDetailf(errBadActionType, "no action type provided on action %d", i)
-               }
-               decoder, ok := a.actionDecoder(typ)
-               if !ok {
-                       return nil, errors.WithDetailf(errBadActionType, "unknown action type %q on action %d", typ, i)
-               }
-
-               // Remarshal to JSON, the action may have been modified when we
-               // filtered aliases.
-               b, err := json.Marshal(act)
-               if err != nil {
-                       return nil, err
-               }
-               action, err := decoder(b)
-               if err != nil {
-                       return nil, errors.WithDetailf(errBadAction, "%s on action %d", err.Error(), i)
-               }
-               actions = append(actions, action)
-       }
-
-       ttl := req.TTL.Duration
-       if ttl == 0 {
-               ttl = defaultTxTTL
-       }
-       maxTime := time.Now().Add(ttl)
-
-       tpl, err := txbuilder.Build(ctx, req.Tx, actions, maxTime, req.TimeRange)
-       if errors.Root(err) == txbuilder.ErrAction {
-               // append each of the inner errors contained in the data.
-               var Errs string
-               for _, innerErr := range errors.Data(err)["actions"].([]error) {
-                       Errs = Errs + "<" + innerErr.Error() + ">"
-               }
-               err = errors.New(err.Error() + "-" + Errs)
-       }
-       if err != nil {
-               return nil, err
-       }
-
-       // ensure null is never returned for signing instructions
-       if tpl.SigningInstructions == nil {
-               tpl.SigningInstructions = []*txbuilder.SigningInstruction{}
-       }
-       return tpl, nil
-}
-
-// POST /build-transaction
-func (a *API) build(ctx context.Context, buildReqs *BuildRequest) Response {
-       subctx := reqid.NewSubContext(ctx, reqid.New())
-
-       tmpl, err := a.buildSingle(subctx, buildReqs)
-       if err != nil {
-               return NewErrorResponse(err)
-       }
-
-       return NewSuccessResponse(tmpl)
-}
-
-func (a *API) submitSingle(ctx context.Context, tpl *txbuilder.Template) (map[string]string, error) {
-       if tpl.Transaction == nil {
-               return nil, errors.Wrap(txbuilder.ErrMissingRawTx)
-       }
-
-       if err := txbuilder.FinalizeTx(ctx, a.chain, tpl.Transaction); err != nil {
-               return nil, errors.Wrapf(err, "tx %s", tpl.Transaction.ID.String())
-       }
-
-       return map[string]string{"tx_id": tpl.Transaction.ID.String()}, nil
-}
-
 // finalizeTxWait calls FinalizeTx and then waits for confirmation of
 // the transaction.  A nil error return means the transaction is
 // confirmed on the blockchain.  ErrRejected means a conflicting tx is
@@ -215,40 +76,3 @@ func (bcr *BlockchainReactor) waitForTxInBlock(ctx context.Context, tx *types.Tx
                }
        }
 }
-
-type submitTxResp struct {
-       TxID *bc.Hash `json:"tx_id"`
-}
-
-// POST /submit-transaction
-func (a *API) submit(ctx context.Context, ins struct {
-       Tx types.Tx `json:"raw_transaction"`
-}) Response {
-       if err := txbuilder.FinalizeTx(ctx, a.chain, &ins.Tx); err != nil {
-               return NewErrorResponse(err)
-       }
-
-       log.WithField("tx_id", ins.Tx.ID).Info("submit single tx")
-       return NewSuccessResponse(&submitTxResp{TxID: &ins.Tx.ID})
-}
-
-// POST /sign-submit-transaction
-func (a *API) signSubmit(ctx context.Context, x struct {
-       Password []string           `json:"password"`
-       Txs      txbuilder.Template `json:"transaction"`
-}) Response {
-       if err := txbuilder.Sign(ctx, &x.Txs, nil, x.Password[0], a.pseudohsmSignTemplate); err != nil {
-               log.WithField("build err", err).Error("fail on sign transaction.")
-               return NewErrorResponse(err)
-       }
-       log.Info("Sign Transaction complete.")
-
-       txID, err := a.submitSingle(nil, &x.Txs)
-       if err != nil {
-               log.WithField("err", err).Error("submit single tx")
-               return NewErrorResponse(err)
-       }
-
-       log.WithField("tx_id", txID["tx_id"]).Info("submit single tx")
-       return NewSuccessResponse(txID)
-}