OSDN Git Service

Feat(ed25519): replace with crypto/ed25519 (#1907)
[bytom/bytom.git] / api / query.go
index 50889ce..83154b3 100644 (file)
@@ -2,27 +2,40 @@ package api
 
 import (
        "context"
+       "crypto/ed25519"
        "encoding/hex"
        "fmt"
 
        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/errors"
-       "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/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)
@@ -40,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
@@ -59,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)
        }
@@ -107,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 {
@@ -151,13 +189,21 @@ func (a *API) getUnconfirmedTx(ctx context.Context, filter struct {
        }
 
        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: false,
+               ID:        txDesc.Tx.ID,
+               Version:   txDesc.Tx.Version,
+               Size:      txDesc.Tx.SerializedSize,
+               TimeRange: txDesc.Tx.TimeRange,
+               Inputs:    []*query.AnnotatedInput{},
+               Outputs:   []*query.AnnotatedOutput{},
+       }
+
+       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 {
@@ -199,7 +245,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
@@ -222,33 +268,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 {
@@ -290,6 +332,21 @@ 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"`
@@ -309,25 +366,51 @@ func (a *API) listPubKeys(ctx context.Context, ins struct {
        }
 
        pubKeyInfos := []PubKeyInfo{}
-       idx := a.wallet.AccountMgr.GetContractIndex(account.ID)
-       for i := uint64(1); i <= idx; i++ {
-               rawPath := signers.Path(account.Signer, signers.AccountKeySpace, i)
-               derivedXPub := account.XPubs[0].Derive(rawPath)
-               pubkey := derivedXPub.PublicKey()
-
-               if ins.PublicKey != "" && ins.PublicKey != hex.EncodeToString(pubkey) {
-                       continue
+       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,
+                       })
                }
-
-               var path []chainjson.HexBytes
-               for _, p := range rawPath {
-                       path = append(path, chainjson.HexBytes(p))
+       } 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,
+                       })
                }
 
-               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 {