+++ /dev/null
-package api
-
-import (
- "context"
- "encoding/hex"
- "encoding/json"
- "fmt"
-
- "github.com/vapor/blockchain/txbuilder"
- "github.com/vapor/crypto/ed25519"
-
- log "github.com/sirupsen/logrus"
-
- "github.com/vapor/account"
- "github.com/vapor/blockchain/query"
- "github.com/vapor/blockchain/signers"
- bytomtypes "github.com/vapor/claim/bytom/protocolbc/types"
- "github.com/vapor/consensus"
- "github.com/vapor/crypto/ed25519/chainkd"
- chainjson "github.com/vapor/encoding/json"
- "github.com/vapor/errors"
- "github.com/vapor/protocol/bc"
- "github.com/vapor/protocol/bc/types"
-)
-
-// POST /list-accounts
-func (a *API) listAccounts(ctx context.Context, filter struct {
- ID string `json:"id"`
- Alias string `json:"alias"`
-}) Response {
- accountID := filter.ID
- if filter.Alias != "" {
- acc, err := a.wallet.AccountMgr.FindByAlias(filter.Alias)
- if err != nil {
- return NewErrorResponse(err)
- }
- accountID = acc.ID
- }
-
- accounts, err := a.wallet.AccountMgr.ListAccounts(accountID)
- if err != nil {
- log.Errorf("listAccounts: %v", err)
- return NewErrorResponse(err)
- }
-
- annotatedAccounts := []query.AnnotatedAccount{}
- for _, acc := range accounts {
- annotatedAccounts = append(annotatedAccounts, *account.Annotated(acc))
- }
-
- return NewSuccessResponse(annotatedAccounts)
-}
-
-// POST /get-asset
-func (a *API) getAsset(ctx context.Context, filter struct {
- ID string `json:"id"`
-}) Response {
- asset, err := a.wallet.AssetReg.GetAsset(filter.ID)
- if err != nil {
- log.Errorf("getAsset: %v", err)
- return NewErrorResponse(err)
- }
-
- return NewSuccessResponse(asset)
-}
-
-// POST /list-assets
-func (a *API) listAssets(ctx context.Context, filter struct {
- ID string `json:"id"`
-}) Response {
- assets, err := a.wallet.AssetReg.ListAssets(filter.ID)
- if err != nil {
- log.Errorf("listAssets: %v", err)
- return NewErrorResponse(err)
- }
-
- return NewSuccessResponse(assets)
-}
-
-// POST /list-balances
-func (a *API) listBalances(ctx context.Context, filter struct {
- AccountID string `json:"account_id"`
- AccountAlias string `json:"account_alias"`
-}) Response {
- accountID := filter.AccountID
- if filter.AccountAlias != "" {
- acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
- if err != nil {
- return NewErrorResponse(err)
- }
- accountID = acc.ID
- }
-
- balances, err := a.wallet.GetAccountBalances(accountID, "")
- if err != nil {
- return NewErrorResponse(err)
- }
- return NewSuccessResponse(balances)
-}
-
-// POST /get-transaction
-func (a *API) getTransaction(ctx context.Context, txInfo struct {
- TxID string `json:"tx_id"`
-}) Response {
- var annotatedTx *query.AnnotatedTx
- var err error
-
- annotatedTx, err = a.wallet.GetTransactionByTxID(txInfo.TxID)
- if err != nil {
- // transaction not found in blockchain db, search it from unconfirmed db
- annotatedTx, err = a.wallet.GetUnconfirmedTxByTxID(txInfo.TxID)
- if err != nil {
- return NewErrorResponse(err)
- }
- }
-
- return NewSuccessResponse(annotatedTx)
-}
-
-// POST /list-transactions
-func (a *API) listTransactions(ctx context.Context, filter struct {
- ID string `json:"id"`
- AccountID string `json:"account_id"`
- Detail bool `json:"detail"`
- Unconfirmed bool `json:"unconfirmed"`
- From uint `json:"from"`
- Count uint `json:"count"`
-}) Response {
- transactions := []*query.AnnotatedTx{}
- var err error
- var transaction *query.AnnotatedTx
-
- if filter.ID != "" {
- transaction, err = a.wallet.GetTransactionByTxID(filter.ID)
- if err != nil && filter.Unconfirmed {
- transaction, err = a.wallet.GetUnconfirmedTxByTxID(filter.ID)
- if err != nil {
- return NewErrorResponse(err)
- }
- }
- transactions = []*query.AnnotatedTx{transaction}
- } else {
- transactions, err = a.wallet.GetTransactions(filter.AccountID)
- if err != nil {
- return NewErrorResponse(err)
- }
-
- if filter.Unconfirmed {
- unconfirmedTxs, err := a.wallet.GetUnconfirmedTxs(filter.AccountID)
- if err != nil {
- return NewErrorResponse(err)
- }
- transactions = append(unconfirmedTxs, transactions...)
- }
- }
-
- if filter.Detail == false {
- txSummary := a.wallet.GetTransactionsSummary(transactions)
- start, end := getPageRange(len(txSummary), filter.From, filter.Count)
- return NewSuccessResponse(txSummary[start:end])
- }
- start, end := getPageRange(len(transactions), filter.From, filter.Count)
- return NewSuccessResponse(transactions[start:end])
-}
-
-// POST /get-unconfirmed-transaction
-func (a *API) getUnconfirmedTx(ctx context.Context, filter struct {
- TxID chainjson.HexBytes `json:"tx_id"`
-}) Response {
- var tmpTxID [32]byte
- copy(tmpTxID[:], filter.TxID[:])
-
- txHash := bc.NewHash(tmpTxID)
- txPool := a.chain.GetTxPool()
- txDesc, err := txPool.GetTransaction(&txHash)
- if err != nil {
- return NewErrorResponse(err)
- }
-
- tx := &BlockTx{
- ID: txDesc.Tx.ID,
- Version: txDesc.Tx.Version,
- Size: txDesc.Tx.SerializedSize,
- TimeRange: txDesc.Tx.TimeRange,
- Inputs: []*query.AnnotatedInput{},
- Outputs: []*query.AnnotatedOutput{},
- StatusFail: txDesc.StatusFail,
- }
-
- resOutID := txDesc.Tx.ResultIds[0]
- resOut := txDesc.Tx.Entries[*resOutID]
- switch out := resOut.(type) {
- case *bc.Output:
- tx.MuxID = *out.Source.Ref
- case *bc.Retirement:
- tx.MuxID = *out.Source.Ref
- }
-
- for i := range txDesc.Tx.Inputs {
- tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(txDesc.Tx, uint32(i)))
- }
- for i := range txDesc.Tx.Outputs {
- tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(txDesc.Tx, i))
- }
-
- return NewSuccessResponse(tx)
-}
-
-type unconfirmedTxsResp struct {
- Total uint64 `json:"total"`
- TxIDs []bc.Hash `json:"tx_ids"`
-}
-
-// POST /list-unconfirmed-transactions
-func (a *API) listUnconfirmedTxs(ctx context.Context) Response {
- txIDs := []bc.Hash{}
-
- txPool := a.chain.GetTxPool()
- txs := txPool.GetTransactions()
- for _, txDesc := range txs {
- txIDs = append(txIDs, bc.Hash(txDesc.Tx.ID))
- }
-
- return NewSuccessResponse(&unconfirmedTxsResp{
- Total: uint64(len(txIDs)),
- TxIDs: txIDs,
- })
-}
-
-// RawTx is the tx struct for getRawTransaction
-type RawTx struct {
- ID bc.Hash `json:"tx_id"`
- Version uint64 `json:"version"`
- Size uint64 `json:"size"`
- TimeRange uint64 `json:"time_range"`
- Inputs []*query.AnnotatedInput `json:"inputs"`
- Outputs []*query.AnnotatedOutput `json:"outputs"`
- Fee uint64 `json:"fee"`
-}
-
-// POST /decode-raw-transaction
-func (a *API) decodeRawTransaction(ctx context.Context, ins struct {
- Tx types.Tx `json:"raw_transaction"`
-}) Response {
- tx := &RawTx{
- ID: ins.Tx.ID,
- Version: ins.Tx.Version,
- Size: ins.Tx.SerializedSize,
- TimeRange: ins.Tx.TimeRange,
- Inputs: []*query.AnnotatedInput{},
- Outputs: []*query.AnnotatedOutput{},
- }
-
- for i := range ins.Tx.Inputs {
- tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(&ins.Tx, uint32(i)))
- }
- for i := range ins.Tx.Outputs {
- tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(&ins.Tx, i))
- }
-
- tx.Fee = txbuilder.CalculateTxFee(&ins.Tx)
- return NewSuccessResponse(tx)
-}
-
-// POST /list-unspent-outputs
-func (a *API) listUnspentOutputs(ctx context.Context, filter struct {
- AccountID string `json:"account_id"`
- AccountAlias string `json:"account_alias"`
- ID string `json:"id"`
- Unconfirmed bool `json:"unconfirmed"`
- SmartContract bool `json:"smart_contract"`
- From uint `json:"from"`
- Count uint `json:"count"`
-}) Response {
- accountID := filter.AccountID
- if filter.AccountAlias != "" {
- acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
- if err != nil {
- return NewErrorResponse(err)
- }
- accountID = acc.ID
- }
- accountUTXOs := a.wallet.GetAccountUtxos(accountID, filter.ID, filter.Unconfirmed, filter.SmartContract)
-
- UTXOs := []query.AnnotatedUTXO{}
- for _, utxo := range accountUTXOs {
- UTXOs = append([]query.AnnotatedUTXO{{
- AccountID: utxo.AccountID,
- OutputID: utxo.OutputID.String(),
- SourceID: utxo.SourceID.String(),
- AssetID: utxo.AssetID.String(),
- Amount: utxo.Amount,
- SourcePos: utxo.SourcePos,
- Program: fmt.Sprintf("%x", utxo.ControlProgram),
- ControlProgramIndex: utxo.ControlProgramIndex,
- Address: utxo.Address,
- ValidHeight: utxo.ValidHeight,
- Alias: a.wallet.AccountMgr.GetAliasByID(utxo.AccountID),
- AssetAlias: a.wallet.AssetReg.GetAliasByID(utxo.AssetID.String()),
- Change: utxo.Change,
- }}, UTXOs...)
- }
- start, end := getPageRange(len(UTXOs), filter.From, filter.Count)
- return NewSuccessResponse(UTXOs[start:end])
-}
-
-// return gasRate
-func (a *API) gasRate() Response {
- gasrate := map[string]int64{"gas_rate": consensus.VMGasRate}
- return NewSuccessResponse(gasrate)
-}
-
-// PubKeyInfo is structure of pubkey info
-type PubKeyInfo struct {
- Pubkey string `json:"pubkey"`
- Path []chainjson.HexBytes `json:"derivation_path"`
-}
-
-// AccountPubkey is detail of account pubkey info
-type AccountPubkey struct {
- RootXPub chainkd.XPub `json:"root_xpub"`
- PubKeyInfos []PubKeyInfo `json:"pubkey_infos"`
-}
-
-func getPubkey(account *account.Account, change bool, index uint64) (*ed25519.PublicKey, []chainjson.HexBytes, error) {
- rawPath, err := signers.Path(account.Signer, signers.AccountKeySpace, change, index)
- if err != nil {
- return nil, nil, err
- }
- derivedXPub := account.XPubs[0].Derive(rawPath)
- pubkey := derivedXPub.PublicKey()
- var path []chainjson.HexBytes
- for _, p := range rawPath {
- path = append(path, chainjson.HexBytes(p))
- }
-
- return &pubkey, path, nil
-}
-
-// POST /list-pubkeys
-func (a *API) listPubKeys(ctx context.Context, ins struct {
- AccountID string `json:"account_id"`
- AccountAlias string `json:"account_alias"`
- PublicKey string `json:"public_key"`
-}) Response {
- var err error
- account := &account.Account{}
- if ins.AccountAlias != "" {
- account, err = a.wallet.AccountMgr.FindByAlias(ins.AccountAlias)
- } else {
- account, err = a.wallet.AccountMgr.FindByID(ins.AccountID)
- }
-
- if err != nil {
- return NewErrorResponse(err)
- }
-
- pubKeyInfos := []PubKeyInfo{}
- if account.DeriveRule == signers.BIP0032 {
- idx := a.wallet.AccountMgr.GetContractIndex(account.ID)
- for i := uint64(1); i <= idx; i++ {
- pubkey, path, err := getPubkey(account, false, i)
- if err != nil {
- return NewErrorResponse(err)
- }
- if ins.PublicKey != "" && ins.PublicKey != hex.EncodeToString(*pubkey) {
- continue
- }
- pubKeyInfos = append(pubKeyInfos, PubKeyInfo{
- Pubkey: hex.EncodeToString(*pubkey),
- Path: path,
- })
- }
- } else if account.DeriveRule == signers.BIP0044 {
- idx := a.wallet.AccountMgr.GetBip44ContractIndex(account.ID, true)
- for i := uint64(1); i <= idx; i++ {
- pubkey, path, err := getPubkey(account, true, i)
- if err != nil {
- return NewErrorResponse(err)
- }
- if ins.PublicKey != "" && ins.PublicKey != hex.EncodeToString(*pubkey) {
- continue
- }
- pubKeyInfos = append(pubKeyInfos, PubKeyInfo{
- Pubkey: hex.EncodeToString(*pubkey),
- Path: path,
- })
- }
-
- idx = a.wallet.AccountMgr.GetBip44ContractIndex(account.ID, false)
- for i := uint64(1); i <= idx; i++ {
- pubkey, path, err := getPubkey(account, false, i)
- if err != nil {
- return NewErrorResponse(err)
- }
- if ins.PublicKey != "" && ins.PublicKey != hex.EncodeToString(*pubkey) {
- continue
- }
- pubKeyInfos = append(pubKeyInfos, PubKeyInfo{
- Pubkey: hex.EncodeToString(*pubkey),
- Path: path,
- })
- }
- }
-
- if len(pubKeyInfos) == 0 {
- return NewErrorResponse(errors.New("Not found publickey for the account"))
- }
-
- return NewSuccessResponse(&AccountPubkey{
- RootXPub: account.XPubs[0],
- PubKeyInfos: pubKeyInfos,
- })
-}
-
-type GetRawTransationResp struct {
- Tx *bytomtypes.Tx `json:"raw_transaction"`
- BlockHash bc.Hash `json:"block_hash"`
-}
-
-func (a *API) getRawTransaction(ins struct {
- RawBlock string `json:"raw_block"`
- TxID string `json:"tx_id"`
-}) Response {
-
- var rawTransaction *bytomtypes.Tx
- block := &bytomtypes.Block{}
- err := block.UnmarshalText([]byte(ins.RawBlock))
- if err != nil {
- return NewErrorResponse(err)
- }
-
- txID := bc.Hash{}
- txID.UnmarshalText([]byte(ins.TxID))
- for _, tx := range block.Transactions {
- if tx.ID.String() == txID.String() {
- rawTransaction = tx
- break
- }
- }
- if rawTransaction == nil {
- return NewErrorResponse(errors.New("raw transaction do not find"))
- }
- resp := GetRawTransationResp{Tx: rawTransaction, BlockHash: block.Hash()}
- return NewSuccessResponse(resp)
-}
-
-type GetSideRawTransationResp struct {
- Tx *types.Tx `json:"raw_transaction"`
- BlockHash bc.Hash `json:"block_hash"`
-}
-
-func (a *API) getSideRawTransaction(ins struct {
- BlockHeight uint64 `json:"block_height"`
- TxID string `json:"tx_id"`
-}) Response {
- block, err := a.chain.GetBlockByHeight(ins.BlockHeight)
- if err != nil {
- return NewErrorResponse(err)
- }
-
- var rawTransaction *types.Tx
-
- txID := bc.Hash{}
- txID.UnmarshalText([]byte(ins.TxID))
-
- for _, tx := range block.Transactions {
- if tx.ID.String() == txID.String() {
- rawTransaction = tx
- break
- }
- }
- if rawTransaction == nil {
- return NewErrorResponse(errors.New("raw transaction do not find"))
- }
- resp := GetSideRawTransationResp{Tx: rawTransaction, BlockHash: block.Hash()}
- return NewSuccessResponse(resp)
-}
-
-type utxoResp struct {
- Utxo []byte `json:"utxo"`
-}
-
-func (a *API) getUnspentOutputs(ins struct {
- RawBlock string `json:"raw_block"`
- TxID string `json:"tx_id"`
- ID string `json:"id"`
- Address string `json:"address"`
-}) Response {
- var rawTransaction *bytomtypes.Tx
- block := &bytomtypes.Block{}
- if err := block.UnmarshalText([]byte(ins.RawBlock)); err != nil {
- return NewErrorResponse(err)
- }
-
- txID := bc.Hash{}
- txID.UnmarshalText([]byte(ins.TxID))
-
- for _, tx := range block.Transactions {
- if tx.ID.String() == txID.String() {
- rawTransaction = tx
- break
- }
- }
- utxo := account.UTXO{}
-
- for i, out := range rawTransaction.Outputs {
- key := rawTransaction.ResultIds[i]
- if key.String() == ins.ID {
- outPut, err := rawTransaction.Output(*key)
- if err != nil {
- continue
- }
- outputID := bc.Hash{
- V0: key.GetV0(),
- V1: key.GetV1(),
- V2: key.GetV2(),
- V3: key.GetV3(),
- }
-
- assetID := bc.AssetID{
- V0: out.AssetAmount.AssetId.GetV0(),
- V1: out.AssetAmount.AssetId.GetV1(),
- V2: out.AssetAmount.AssetId.GetV2(),
- V3: out.AssetAmount.AssetId.GetV3(),
- }
-
- sourceID := bc.Hash{
- V0: outPut.Source.Ref.GetV0(),
- V1: outPut.Source.Ref.GetV1(),
- V2: outPut.Source.Ref.GetV2(),
- V3: outPut.Source.Ref.GetV3(),
- }
- utxo = account.UTXO{
- OutputID: outputID,
- AssetID: assetID,
- Amount: out.Amount,
- ControlProgram: out.ControlProgram,
- SourceID: sourceID,
- SourcePos: outPut.Source.Position,
- ValidHeight: block.Height,
- Address: ins.Address,
- }
- }
- }
-
- resp, err := json.Marshal(&utxo)
- if err != nil {
- return NewErrorResponse(err)
- }
-
- return NewSuccessResponse(&utxoResp{Utxo: resp})
-}