-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"crypto/tls"
cmn "github.com/tendermint/tmlibs/common"
"github.com/bytom/accesstoken"
+ "github.com/bytom/blockchain"
cfg "github.com/bytom/config"
"github.com/bytom/dashboard"
"github.com/bytom/errors"
// SUCCESS indicates the rpc calling is successful.
SUCCESS = "success"
// FAIL indicated the rpc calling is failed.
- FAIL = "fail"
+ FAIL = "fail"
+ crosscoreRPCPrefix = "/rpc/"
)
// Response describes the response standard.
}
type API struct {
- bcr *BlockchainReactor
+ bcr *blockchain.BlockchainReactor
wallet *wallet.Wallet
chain *protocol.Chain
server *http.Server
}()
}
-func NewAPI(bcr *BlockchainReactor, config *cfg.Config) *API {
+func NewAPI(bcr *blockchain.BlockchainReactor, wallet *wallet.Wallet, chain *protocol.Chain, config *cfg.Config) *API {
api := &API{
bcr: bcr,
- wallet: bcr.wallet,
- chain: bcr.chain,
+ wallet: wallet,
+ chain: chain,
}
api.buildHandler()
api.initServer(config)
-package blockchain
+package api
import (
"context"
--- /dev/null
+package api
+
+import (
+ log "github.com/sirupsen/logrus"
+
+ "github.com/bytom/blockchain/query"
+ "github.com/bytom/wallet"
+ "github.com/bytom/consensus"
+ "github.com/bytom/consensus/difficulty"
+ chainjson "github.com/bytom/encoding/json"
+ "github.com/bytom/protocol/bc"
+ "github.com/bytom/protocol/bc/types"
+)
+
+// return network infomation
+func (a *API) getNetInfo() Response {
+ return NewSuccessResponse(a.bcr.GetNodeInfo())
+}
+
+// return best block hash
+func (a *API) getBestBlockHash() Response {
+ blockHash := map[string]string{"blockHash": a.chain.BestBlockHash().String()}
+ return NewSuccessResponse(blockHash)
+}
+
+// return block header by hash
+func (a *API) getBlockHeaderByHash(strHash string) Response {
+ hash := bc.Hash{}
+ if err := hash.UnmarshalText([]byte(strHash)); err != nil {
+ log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
+ return NewErrorResponse(err)
+ }
+ block, err := a.chain.GetBlockByHash(&hash)
+ if err != nil {
+ log.WithField("error", err).Error("Fail to get block by hash")
+ return NewErrorResponse(err)
+ }
+
+ bcBlock := types.MapBlock(block)
+ return NewSuccessResponse(bcBlock.BlockHeader)
+}
+
+// BlockTx is the tx struct for getBlock func
+type BlockTx struct {
+ ID bc.Hash `json:"id"`
+ Version uint64 `json:"version"`
+ Size uint64 `json:"size"`
+ TimeRange uint64 `json:"time_range"`
+ Inputs []*query.AnnotatedInput `json:"inputs"`
+ Outputs []*query.AnnotatedOutput `json:"outputs"`
+ StatusFail bool `json:"status_fail"`
+}
+
+// GetBlockReq is used to handle getBlock req
+type GetBlockReq struct {
+ BlockHeight uint64 `json:"block_height"`
+ BlockHash chainjson.HexBytes `json:"block_hash"`
+}
+
+// GetBlockResp is the resp for getBlock api
+type GetBlockResp struct {
+ Hash *bc.Hash `json:"hash"`
+ Size uint64 `json:"size"`
+ Version uint64 `json:"version"`
+ Height uint64 `json:"height"`
+ PreviousBlockHash *bc.Hash `json:"previous_block_hash"`
+ Timestamp uint64 `json:"timestamp"`
+ Nonce uint64 `json:"nonce"`
+ Bits uint64 `json:"bits"`
+ Difficulty string `json:"difficulty"`
+ TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
+ TransactionStatusHash *bc.Hash `json:"transaction_status_hash"`
+ Transactions []*BlockTx `json:"transactions"`
+}
+
+// return block by hash
+func (a *API) getBlock(ins GetBlockReq) Response {
+ var err error
+ block := &types.Block{}
+ if len(ins.BlockHash) == 32 {
+ b32 := [32]byte{}
+ copy(b32[:], ins.BlockHash)
+ hash := bc.NewHash(b32)
+ block, err = a.chain.GetBlockByHash(&hash)
+ } else {
+ block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
+ }
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ blockHash := block.Hash()
+ txStatus, err := a.chain.GetTransactionStatus(&blockHash)
+ rawBlock, err := block.MarshalText()
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ resp := &GetBlockResp{
+ Hash: &blockHash,
+ Size: uint64(len(rawBlock)),
+ Version: block.Version,
+ Height: block.Height,
+ PreviousBlockHash: &block.PreviousBlockHash,
+ Timestamp: block.Timestamp,
+ Nonce: block.Nonce,
+ Bits: block.Bits,
+ Difficulty: difficulty.CompactToBig(block.Bits).String(),
+ TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
+ TransactionStatusHash: &block.TransactionStatusHash,
+ Transactions: []*BlockTx{},
+ }
+
+ for i, orig := range block.Transactions {
+ tx := &BlockTx{
+ ID: orig.ID,
+ Version: orig.Version,
+ Size: orig.SerializedSize,
+ TimeRange: orig.TimeRange,
+ Inputs: []*query.AnnotatedInput{},
+ Outputs: []*query.AnnotatedOutput{},
+ }
+ tx.StatusFail, err = txStatus.GetStatus(i)
+ if err != nil {
+ NewSuccessResponse(resp)
+ }
+
+ for i := range orig.Inputs {
+ tx.Inputs = append(tx.Inputs, wallet.BuildAnnotatedInput(orig, uint32(i)))
+ }
+ for i := range orig.Outputs {
+ tx.Outputs = append(tx.Outputs, wallet.BuildAnnotatedOutput(orig, i))
+ }
+ resp.Transactions = append(resp.Transactions, tx)
+ }
+ return NewSuccessResponse(resp)
+}
+
+// return block transactions count by hash
+func (a *API) getBlockTransactionsCountByHash(strHash string) Response {
+ hash := bc.Hash{}
+ if err := hash.UnmarshalText([]byte(strHash)); err != nil {
+ log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
+ return NewErrorResponse(err)
+ }
+
+ legacyBlock, err := a.chain.GetBlockByHash(&hash)
+ if err != nil {
+ log.WithField("error", err).Error("Fail to get block by hash")
+ return NewErrorResponse(err)
+ }
+
+ count := map[string]int{"count": len(legacyBlock.Transactions)}
+ return NewSuccessResponse(count)
+}
+
+// return block transactions count by height
+func (a *API) getBlockTransactionsCountByHeight(height uint64) Response {
+ legacyBlock, err := a.chain.GetBlockByHeight(height)
+ if err != nil {
+ log.WithField("error", err).Error("Fail to get block by hash")
+ return NewErrorResponse(err)
+ }
+
+ count := map[string]int{"count": len(legacyBlock.Transactions)}
+ return NewSuccessResponse(count)
+}
+
+// return current block count
+func (a *API) getBlockCount() Response {
+ blockHeight := map[string]uint64{"block_count": a.chain.Height()}
+ return NewSuccessResponse(blockHeight)
+}
+
+// return is in mining or not
+func (a *API) isMining() Response {
+ IsMining := map[string]bool{"isMining": a.bcr.IsMining()}
+ return NewSuccessResponse(IsMining)
+}
+
+// return gasRate
+func (a *API) gasRate() Response {
+ gasrate := map[string]int64{"gasRate": consensus.VMGasRate}
+ return NewSuccessResponse(gasrate)
+}
-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"expvar"
--- /dev/null
+package api
+
+import (
+ "context"
+
+ "github.com/bytom/protocol/bc/types"
+)
+
+func (a *API) getWork() Response {
+ work, err := a.bcr.GetWork()
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(work)
+}
+
+func (a *API) submitWork(bh *types.BlockHeader) Response {
+ return NewSuccessResponse(a.bcr.SubmitWork(bh))
+}
+
+func (a *API) getBlockHeaderByHeight(ctx context.Context, req struct {
+ Height uint64 `json:"block_height"`
+}) Response {
+ block, err := a.chain.GetBlockByHeight(req.Height)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ resp := &BlockHeaderByHeight{
+ BlockHeader: &block.BlockHeader,
+ Reward: block.Transactions[0].Outputs[0].Amount,
+ }
+ return NewSuccessResponse(resp)
+}
-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"context"
-package blockchain
+package api
import (
"context"
--- /dev/null
+package api
+
+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
+}
+
+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)
+}
-package blockchain
+package api
import (
"encoding/json"
--- /dev/null
+package api
+
+import (
+ "context"
+ "encoding/json"
+
+ log "github.com/sirupsen/logrus"
+
+ "github.com/bytom/blockchain/txfeed"
+)
+
+// POST /create-txfeed
+func (a *API) createTxFeed(ctx context.Context, in struct {
+ Alias string `json:"alias"`
+ Filter string `json:"filter"`
+}) Response {
+ if err := a.bcr.TxFeedTracker.Create(ctx, in.Alias, in.Filter); err != nil {
+ log.WithField("error", err).Error("Add TxFeed Failed")
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(nil)
+}
+
+// POST /get-transaction-feed
+func (a *API) getTxFeed(ctx context.Context, in struct {
+ Alias string `json:"alias,omitempty"`
+}) Response {
+ var tmpTxFeed interface{}
+ rawTxfeed, err := a.bcr.GetTxFeedByAlias(ctx, in.Alias)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ err = json.Unmarshal(rawTxfeed, &tmpTxFeed)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ data := map[string]interface{}{"txfeed": tmpTxFeed}
+ return NewSuccessResponse(data)
+}
+
+// POST /delete-transaction-feed
+func (a *API) deleteTxFeed(ctx context.Context, in struct {
+ Alias string `json:"alias,omitempty"`
+}) Response {
+ if err := a.bcr.TxFeedTracker.Delete(ctx, in.Alias); err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(nil)
+}
+
+// POST /update-transaction-feed
+func (a *API) updateTxFeed(ctx context.Context, in struct {
+ Alias string `json:"alias"`
+ Filter string `json:"filter"`
+}) Response {
+ if err := a.bcr.TxFeedTracker.Delete(ctx, in.Alias); err != nil {
+ return NewErrorResponse(err)
+ }
+ if err := a.bcr.TxFeedTracker.Create(ctx, in.Alias, in.Filter); err != nil {
+ log.WithField("error", err).Error("Update TxFeed Failed")
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(nil)
+}
+
+func (a *API) getTxFeeds() ([]txfeed.TxFeed, error) {
+ txFeed := txfeed.TxFeed{}
+ txFeeds := make([]txfeed.TxFeed, 0)
+
+ iter := a.bcr.TxFeedTracker.DB.Iterator()
+ defer iter.Release()
+
+ for iter.Next() {
+ if err := json.Unmarshal(iter.Value(), &txFeed); err != nil {
+ return nil, err
+ }
+ txFeeds = append(txFeeds, txFeed)
+ }
+
+ return txFeeds, nil
+}
+
+// listTxFeeds is an http handler for listing txfeeds. It does not take a filter.
+// POST /list-transaction-feeds
+func (a *API) listTxFeeds(ctx context.Context) Response {
+ txFeeds, err := a.getTxFeeds()
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+
+ return NewSuccessResponse(txFeeds)
+}
package api
import (
- "github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
)
BlockHeader *types.BlockHeader `json:"block_header"`
Reward uint64 `json:"reward"`
}
-
-// GetWorkResp is resp struct for API
-type GetWorkResp struct {
- BlockHeader *types.BlockHeader `json:"block_header"`
- Seed *bc.Hash `json:"seed"`
-}
-
-type NetInfo struct {
- Listening bool `json:"listening"`
- Syncing bool `json:"syncing"`
- Mining bool `json:"mining"`
- PeerCount int `json:"peer_count"`
- CurrentBlock uint64 `json:"current_block"`
- HighestBlock uint64 `json:"highest_block"`
-}
-package blockchain
+package api
import (
"bytes"
package blockchain
-import (
- log "github.com/sirupsen/logrus"
-
- "github.com/bytom/api"
- "github.com/bytom/blockchain/query"
- "github.com/bytom/wallet"
- "github.com/bytom/consensus"
- "github.com/bytom/consensus/difficulty"
- chainjson "github.com/bytom/encoding/json"
- "github.com/bytom/protocol/bc"
- "github.com/bytom/protocol/bc/types"
-)
+type NetInfo struct {
+ Listening bool `json:"listening"`
+ Syncing bool `json:"syncing"`
+ Mining bool `json:"mining"`
+ PeerCount int `json:"peer_count"`
+ CurrentBlock uint64 `json:"current_block"`
+ HighestBlock uint64 `json:"highest_block"`
+}
-func (bcr *BlockchainReactor) GetNodeInfo() *api.NetInfo {
- return &api.NetInfo{
+func (bcr *BlockchainReactor) GetNodeInfo() *NetInfo {
+ return &NetInfo{
Listening: bcr.sw.IsListening(),
Syncing: bcr.blockKeeper.IsCaughtUp(),
Mining: bcr.mining.IsMining(),
func (bcr *BlockchainReactor) IsMining() bool {
return bcr.mining.IsMining()
}
-
-// return network infomation
-func (a *API) getNetInfo() Response {
- return NewSuccessResponse(a.bcr.GetNodeInfo())
-}
-
-// return best block hash
-func (a *API) getBestBlockHash() Response {
- blockHash := map[string]string{"blockHash": a.chain.BestBlockHash().String()}
- return NewSuccessResponse(blockHash)
-}
-
-// return block header by hash
-func (a *API) getBlockHeaderByHash(strHash string) Response {
- hash := bc.Hash{}
- if err := hash.UnmarshalText([]byte(strHash)); err != nil {
- log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
- return NewErrorResponse(err)
- }
- block, err := a.chain.GetBlockByHash(&hash)
- if err != nil {
- log.WithField("error", err).Error("Fail to get block by hash")
- return NewErrorResponse(err)
- }
-
- bcBlock := types.MapBlock(block)
- return NewSuccessResponse(bcBlock.BlockHeader)
-}
-
-// BlockTx is the tx struct for getBlock func
-type BlockTx struct {
- ID bc.Hash `json:"id"`
- Version uint64 `json:"version"`
- Size uint64 `json:"size"`
- TimeRange uint64 `json:"time_range"`
- Inputs []*query.AnnotatedInput `json:"inputs"`
- Outputs []*query.AnnotatedOutput `json:"outputs"`
- StatusFail bool `json:"status_fail"`
-}
-
-// GetBlockReq is used to handle getBlock req
-type GetBlockReq struct {
- BlockHeight uint64 `json:"block_height"`
- BlockHash chainjson.HexBytes `json:"block_hash"`
-}
-
-// GetBlockResp is the resp for getBlock api
-type GetBlockResp struct {
- Hash *bc.Hash `json:"hash"`
- Size uint64 `json:"size"`
- Version uint64 `json:"version"`
- Height uint64 `json:"height"`
- PreviousBlockHash *bc.Hash `json:"previous_block_hash"`
- Timestamp uint64 `json:"timestamp"`
- Nonce uint64 `json:"nonce"`
- Bits uint64 `json:"bits"`
- Difficulty string `json:"difficulty"`
- TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
- TransactionStatusHash *bc.Hash `json:"transaction_status_hash"`
- Transactions []*BlockTx `json:"transactions"`
-}
-
-// return block by hash
-func (a *API) getBlock(ins GetBlockReq) Response {
- var err error
- block := &types.Block{}
- if len(ins.BlockHash) == 32 {
- b32 := [32]byte{}
- copy(b32[:], ins.BlockHash)
- hash := bc.NewHash(b32)
- block, err = a.chain.GetBlockByHash(&hash)
- } else {
- block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
- }
- if err != nil {
- return NewErrorResponse(err)
- }
-
- blockHash := block.Hash()
- txStatus, err := a.chain.GetTransactionStatus(&blockHash)
- rawBlock, err := block.MarshalText()
- if err != nil {
- return NewErrorResponse(err)
- }
-
- resp := &GetBlockResp{
- Hash: &blockHash,
- Size: uint64(len(rawBlock)),
- Version: block.Version,
- Height: block.Height,
- PreviousBlockHash: &block.PreviousBlockHash,
- Timestamp: block.Timestamp,
- Nonce: block.Nonce,
- Bits: block.Bits,
- Difficulty: difficulty.CompactToBig(block.Bits).String(),
- TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
- TransactionStatusHash: &block.TransactionStatusHash,
- Transactions: []*BlockTx{},
- }
-
- for i, orig := range block.Transactions {
- tx := &BlockTx{
- ID: orig.ID,
- Version: orig.Version,
- Size: orig.SerializedSize,
- TimeRange: orig.TimeRange,
- Inputs: []*query.AnnotatedInput{},
- Outputs: []*query.AnnotatedOutput{},
- }
- tx.StatusFail, err = txStatus.GetStatus(i)
- if err != nil {
- NewSuccessResponse(resp)
- }
-
- for i := range orig.Inputs {
- tx.Inputs = append(tx.Inputs, wallet.BuildAnnotatedInput(orig, uint32(i)))
- }
- for i := range orig.Outputs {
- tx.Outputs = append(tx.Outputs, wallet.BuildAnnotatedOutput(orig, i))
- }
- resp.Transactions = append(resp.Transactions, tx)
- }
- return NewSuccessResponse(resp)
-}
-
-// return block transactions count by hash
-func (a *API) getBlockTransactionsCountByHash(strHash string) Response {
- hash := bc.Hash{}
- if err := hash.UnmarshalText([]byte(strHash)); err != nil {
- log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
- return NewErrorResponse(err)
- }
-
- legacyBlock, err := a.chain.GetBlockByHash(&hash)
- if err != nil {
- log.WithField("error", err).Error("Fail to get block by hash")
- return NewErrorResponse(err)
- }
-
- count := map[string]int{"count": len(legacyBlock.Transactions)}
- return NewSuccessResponse(count)
-}
-
-// return block transactions count by height
-func (a *API) getBlockTransactionsCountByHeight(height uint64) Response {
- legacyBlock, err := a.chain.GetBlockByHeight(height)
- if err != nil {
- log.WithField("error", err).Error("Fail to get block by hash")
- return NewErrorResponse(err)
- }
-
- count := map[string]int{"count": len(legacyBlock.Transactions)}
- return NewSuccessResponse(count)
-}
-
-// return current block count
-func (a *API) getBlockCount() Response {
- blockHeight := map[string]uint64{"block_count": a.chain.Height()}
- return NewSuccessResponse(blockHeight)
-}
-
-// return is in mining or not
-func (a *API) isMining() Response {
- IsMining := map[string]bool{"isMining": a.bcr.IsMining()}
- return NewSuccessResponse(IsMining)
-}
-
-// return gasRate
-func (a *API) gasRate() Response {
- gasrate := map[string]int64{"gasRate": consensus.VMGasRate}
- return NewSuccessResponse(gasrate)
-}
package blockchain
import (
- "context"
-
- "github.com/bytom/api"
+ "github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
)
-func (bcr *BlockchainReactor) GetWork() (*api.GetWorkResp, error) {
+// GetWorkResp is resp struct for API
+type GetWorkResp struct {
+ BlockHeader *types.BlockHeader `json:"block_header"`
+ Seed *bc.Hash `json:"seed"`
+}
+
+func (bcr *BlockchainReactor) GetWork() (*GetWorkResp, error) {
bh, err := bcr.miningPool.GetWork()
if err != nil {
return nil, err
return nil, err
}
- return &api.GetWorkResp{
+ return &GetWorkResp{
BlockHeader: bh,
Seed: seed,
}, nil
func (bcr *BlockchainReactor) SubmitWork(bh *types.BlockHeader) bool {
return bcr.miningPool.SubmitWork(bh)
}
-
-func (a *API) getWork() Response {
- work, err := a.bcr.GetWork()
- if err != nil {
- return NewErrorResponse(err)
- }
- return NewSuccessResponse(work)
-}
-
-func (a *API) submitWork(bh *types.BlockHeader) Response {
- return NewSuccessResponse(a.bcr.SubmitWork(bh))
-}
-
-func (a *API) getBlockHeaderByHeight(ctx context.Context, req struct {
- Height uint64 `json:"block_height"`
-}) Response {
- block, err := a.chain.GetBlockByHeight(req.Height)
- if err != nil {
- return NewErrorResponse(err)
- }
-
- resp := &api.BlockHeaderByHeight{
- BlockHeader: &block.BlockHeader,
- Reward: block.Transactions[0].Outputs[0].Amount,
- }
- return NewSuccessResponse(resp)
-}
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
}
}
}
-
-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)
-}
"context"
"encoding/json"
- log "github.com/sirupsen/logrus"
-
- "github.com/bytom/blockchain/txfeed"
"github.com/bytom/errors"
)
-// POST /create-txfeed
-func (a *API) createTxFeed(ctx context.Context, in struct {
- Alias string `json:"alias"`
- Filter string `json:"filter"`
-}) Response {
- if err := a.bcr.TxFeedTracker.Create(ctx, in.Alias, in.Filter); err != nil {
- log.WithField("error", err).Error("Add TxFeed Failed")
- return NewErrorResponse(err)
- }
- return NewSuccessResponse(nil)
-}
-
-func (bcr *BlockchainReactor) getTxFeedByAlias(ctx context.Context, filter string) ([]byte, error) {
+func (bcr *BlockchainReactor) GetTxFeedByAlias(ctx context.Context, filter string) ([]byte, error) {
jf, err := json.Marshal(filter)
if err != nil {
return nil, err
return value, nil
}
-
-// POST /get-transaction-feed
-func (a *API) getTxFeed(ctx context.Context, in struct {
- Alias string `json:"alias,omitempty"`
-}) Response {
- var tmpTxFeed interface{}
- rawTxfeed, err := a.bcr.getTxFeedByAlias(ctx, in.Alias)
- if err != nil {
- return NewErrorResponse(err)
- }
- err = json.Unmarshal(rawTxfeed, &tmpTxFeed)
- if err != nil {
- return NewErrorResponse(err)
- }
- data := map[string]interface{}{"txfeed": tmpTxFeed}
- return NewSuccessResponse(data)
-}
-
-// POST /delete-transaction-feed
-func (a *API) deleteTxFeed(ctx context.Context, in struct {
- Alias string `json:"alias,omitempty"`
-}) Response {
- if err := a.bcr.TxFeedTracker.Delete(ctx, in.Alias); err != nil {
- return NewErrorResponse(err)
- }
- return NewSuccessResponse(nil)
-}
-
-// POST /update-transaction-feed
-func (a *API) updateTxFeed(ctx context.Context, in struct {
- Alias string `json:"alias"`
- Filter string `json:"filter"`
-}) Response {
- if err := a.bcr.TxFeedTracker.Delete(ctx, in.Alias); err != nil {
- return NewErrorResponse(err)
- }
- if err := a.bcr.TxFeedTracker.Create(ctx, in.Alias, in.Filter); err != nil {
- log.WithField("error", err).Error("Update TxFeed Failed")
- return NewErrorResponse(err)
- }
- return NewSuccessResponse(nil)
-}
-
-func (a *API) getTxFeeds() ([]txfeed.TxFeed, error) {
- txFeed := txfeed.TxFeed{}
- txFeeds := make([]txfeed.TxFeed, 0)
-
- iter := a.bcr.TxFeedTracker.DB.Iterator()
- defer iter.Release()
-
- for iter.Next() {
- if err := json.Unmarshal(iter.Value(), &txFeed); err != nil {
- return nil, err
- }
- txFeeds = append(txFeeds, txFeed)
- }
-
- return txFeeds, nil
-}
-
-// listTxFeeds is an http handler for listing txfeeds. It does not take a filter.
-// POST /list-transaction-feeds
-func (a *API) listTxFeeds(ctx context.Context) Response {
- txFeeds, err := a.getTxFeeds()
- if err != nil {
- return NewErrorResponse(err)
- }
-
- return NewSuccessResponse(txFeeds)
-}
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
- "github.com/bytom/blockchain"
+ "github.com/bytom/api"
"github.com/bytom/crypto/ed25519/chainkd"
"github.com/bytom/util"
)
Short: "Import the private key",
Args: cobra.ExactArgs(5),
Run: func(cmd *cobra.Command, args []string) {
- var params blockchain.KeyImportParams
+ var params api.KeyImportParams
params.KeyAlias = args[0]
params.XPrv = args[1]
params.Password = args[3]
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
- "github.com/bytom/blockchain"
+ "github.com/bytom/api"
"github.com/bytom/blockchain/txbuilder"
"github.com/bytom/protocol/bc/types"
"github.com/bytom/util"
os.Exit(util.ErrLocalExe)
}
- var buildReq blockchain.BuildRequest
+ var buildReq api.BuildRequest
if err := json.Unmarshal([]byte(buildReqStr), &buildReq); err != nil {
jww.ERROR.Println(err)
os.Exit(util.ErrLocalExe)
"fmt"
"os"
- "github.com/bytom/api"
+ "github.com/bytom/blockchain"
"github.com/bytom/consensus/difficulty"
"github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
fmt.Println(err)
os.Exit(1)
}
- resp := &api.GetWorkResp{}
+ resp := &blockchain.GetWorkResp{}
if err = json.Unmarshal(rawData, resp); err != nil {
fmt.Println(err)
os.Exit(1)
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
+ "github.com/bytom/api"
+ "github.com/bytom/crypto/ed25519/chainkd"
+ bc "github.com/bytom/blockchain"
"github.com/bytom/accesstoken"
"github.com/bytom/account"
"github.com/bytom/asset"
- bc "github.com/bytom/blockchain"
"github.com/bytom/blockchain/pseudohsm"
"github.com/bytom/blockchain/txfeed"
cfg "github.com/bytom/config"
- "github.com/bytom/crypto/ed25519/chainkd"
"github.com/bytom/database/leveldb"
"github.com/bytom/env"
"github.com/bytom/p2p"
bcReactor *bc.BlockchainReactor
wallet *w.Wallet
accessTokens *accesstoken.CredentialStore
- api *bc.API
+ api *api.API
+ chain *protocol.Chain
}
func NewNode(config *cfg.Config) *Node {
bcReactor: bcReactor,
accessTokens: accessTokens,
wallet: wallet,
+ chain: chain,
}
node.BaseService = *cmn.NewBaseService(nil, "Node", node)
}
func (n *Node) initAndstartApiServer() {
- n.api = bc.NewAPI(n.bcReactor, n.config)
+ n.api = api.NewAPI(n.bcReactor, n.wallet, n.chain, n.config)
listenAddr := env.String("LISTEN", n.config.ApiAddress)
n.api.StartServer(*listenAddr)
"strings"
"time"
+ "github.com/bytom/api"
"github.com/bytom/blockchain"
"github.com/bytom/blockchain/rpc"
"github.com/bytom/env"
// Wrapper rpc call api.
func ClientCall(path string, req ...interface{}) (interface{}, int) {
- var response = &blockchain.Response{}
+ var response = &api.Response{}
var request interface{}
if req != nil {
client.Call(context.Background(), path, request, response)
switch response.Status {
- case blockchain.FAIL:
+ case api.FAIL:
jww.ERROR.Println(response.Msg)
return nil, ErrRemote
case "":