OSDN Git Service

update doc (#1807)
[bytom/bytom.git] / api / query.go
index 1db5929..3a02781 100644 (file)
@@ -7,21 +7,35 @@ import (
 
        log "github.com/sirupsen/logrus"
 
-       "github.com/bytom/account"
-       "github.com/bytom/blockchain/query"
-       "github.com/bytom/blockchain/signers"
-       "github.com/bytom/consensus"
-       "github.com/bytom/crypto/ed25519/chainkd"
-       chainjson "github.com/bytom/encoding/json"
-       "github.com/bytom/protocol/bc"
-       "github.com/bytom/protocol/bc/types"
+       "github.com/bytom/bytom/account"
+       "github.com/bytom/bytom/asset"
+       "github.com/bytom/bytom/blockchain/query"
+       "github.com/bytom/bytom/blockchain/signers"
+       "github.com/bytom/bytom/blockchain/txbuilder"
+       "github.com/bytom/bytom/consensus"
+       "github.com/bytom/bytom/crypto/ed25519"
+       "github.com/bytom/bytom/crypto/ed25519/chainkd"
+       chainjson "github.com/bytom/bytom/encoding/json"
+       "github.com/bytom/bytom/errors"
+       "github.com/bytom/bytom/protocol/bc"
+       "github.com/bytom/bytom/protocol/bc/types"
 )
 
 // POST /list-accounts
 func (a *API) listAccounts(ctx context.Context, filter struct {
-       ID string `json:"id"`
+       ID    string `json:"id"`
+       Alias string `json:"alias"`
 }) Response {
-       accounts, err := a.wallet.AccountMgr.ListAccounts(filter.ID)
+       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)
@@ -39,13 +53,17 @@ func (a *API) listAccounts(ctx context.Context, filter struct {
 func (a *API) getAsset(ctx context.Context, filter struct {
        ID string `json:"id"`
 }) Response {
-       asset, err := a.wallet.AssetReg.GetAsset(filter.ID)
+       ass, err := a.wallet.AssetReg.GetAsset(filter.ID)
        if err != nil {
                log.Errorf("getAsset: %v", err)
                return NewErrorResponse(err)
        }
 
-       return NewSuccessResponse(asset)
+       annotatedAsset, err := asset.Annotated(ass)
+       if err != nil {
+               return NewErrorResponse(err)
+       }
+       return NewSuccessResponse(annotatedAsset)
 }
 
 // POST /list-assets
@@ -58,12 +76,32 @@ func (a *API) listAssets(ctx context.Context, filter struct {
                return NewErrorResponse(err)
        }
 
-       return NewSuccessResponse(assets)
+       annotatedAssets := []*query.AnnotatedAsset{}
+       for _, ass := range assets {
+               annotatedAsset, err := asset.Annotated(ass)
+               if err != nil {
+                       return NewErrorResponse(err)
+               }
+               annotatedAssets = append(annotatedAssets, annotatedAsset)
+       }
+       return NewSuccessResponse(annotatedAssets)
 }
 
 // POST /list-balances
-func (a *API) listBalances(ctx context.Context) Response {
-       balances, err := a.wallet.GetAccountBalances("")
+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)
        }
@@ -95,6 +133,8 @@ func (a *API) listTransactions(ctx context.Context, filter struct {
        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
@@ -104,9 +144,10 @@ func (a *API) listTransactions(ctx context.Context, filter struct {
                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)
-                       }
+               }
+
+               if err != nil {
+                       return NewErrorResponse(err)
                }
                transactions = []*query.AnnotatedTx{transaction}
        } else {
@@ -126,9 +167,11 @@ func (a *API) listTransactions(ctx context.Context, filter struct {
 
        if filter.Detail == false {
                txSummary := a.wallet.GetTransactionsSummary(transactions)
-               return NewSuccessResponse(txSummary)
+               start, end := getPageRange(len(txSummary), filter.From, filter.Count)
+               return NewSuccessResponse(txSummary[start:end])
        }
-       return NewSuccessResponse(transactions)
+       start, end := getPageRange(len(transactions), filter.From, filter.Count)
+       return NewSuccessResponse(transactions[start:end])
 }
 
 // POST /get-unconfirmed-transaction
@@ -152,7 +195,16 @@ func (a *API) getUnconfirmedTx(ctx context.Context, filter struct {
                TimeRange:  txDesc.Tx.TimeRange,
                Inputs:     []*query.AnnotatedInput{},
                Outputs:    []*query.AnnotatedOutput{},
-               StatusFail: false,
+               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 {
@@ -194,7 +246,7 @@ type RawTx struct {
        TimeRange uint64                   `json:"time_range"`
        Inputs    []*query.AnnotatedInput  `json:"inputs"`
        Outputs   []*query.AnnotatedOutput `json:"outputs"`
-       Fee       int64                    `json:"fee"`
+       Fee       uint64                   `json:"fee"`
 }
 
 // POST /decode-raw-transaction
@@ -217,31 +269,29 @@ func (a *API) decodeRawTransaction(ctx context.Context, ins struct {
                tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(&ins.Tx, i))
        }
 
-       totalInputBtm := uint64(0)
-       totalOutputBtm := uint64(0)
-       for _, input := range tx.Inputs {
-               if input.AssetID.String() == consensus.BTMAssetID.String() {
-                       totalInputBtm += input.Amount
-               }
-       }
-
-       for _, output := range tx.Outputs {
-               if output.AssetID.String() == consensus.BTMAssetID.String() {
-                       totalOutputBtm += output.Amount
-               }
-       }
-
-       tx.Fee = int64(totalInputBtm) - int64(totalOutputBtm)
+       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 {
-       accountUTXOs := a.wallet.GetAccountUtxos(filter.ID, filter.Unconfirmed, filter.SmartContract)
+       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 {
@@ -261,8 +311,8 @@ func (a *API) listUnspentOutputs(ctx context.Context, filter struct {
                        Change:              utxo.Change,
                }}, UTXOs...)
        }
-
-       return NewSuccessResponse(UTXOs)
+       start, end := getPageRange(len(UTXOs), filter.From, filter.Count)
+       return NewSuccessResponse(UTXOs[start:end])
 }
 
 // return gasRate
@@ -283,31 +333,89 @@ type AccountPubkey struct {
        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"`
+       AccountID    string `json:"account_id"`
+       AccountAlias string `json:"account_alias"`
+       PublicKey    string `json:"public_key"`
 }) Response {
-       account, err := a.wallet.AccountMgr.FindByID(ins.AccountID)
+       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{}
-       idx := a.wallet.AccountMgr.GetContractIndex(ins.AccountID)
-       for i := uint64(1); i <= idx; i++ {
-               rawPath := signers.Path(account.Signer, signers.AccountKeySpace, i)
-               derivedXPub := account.XPubs[0].Derive(rawPath)
-               pubkey := derivedXPub.PublicKey()
-
-               var path []chainjson.HexBytes
-               for _, p := range rawPath {
-                       path = append(path, chainjson.HexBytes(p))
+       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,
+                       })
                }
+       }
 
-               pubKeyInfos = append([]PubKeyInfo{{
-                       Pubkey: hex.EncodeToString(pubkey),
-                       Path:   path,
-               }}, pubKeyInfos...)
+       if len(pubKeyInfos) == 0 {
+               return NewErrorResponse(errors.New("Not found publickey for the account"))
        }
 
        return NewSuccessResponse(&AccountPubkey{