github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/api/accounts.go (about)

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"sort"
     7  
     8  	log "github.com/sirupsen/logrus"
     9  
    10  	"github.com/bytom/bytom/account"
    11  	"github.com/bytom/bytom/blockchain/signers"
    12  	"github.com/bytom/bytom/common"
    13  	"github.com/bytom/bytom/consensus"
    14  	"github.com/bytom/bytom/crypto/ed25519/chainkd"
    15  	"github.com/bytom/bytom/protocol/vm/vmutil"
    16  )
    17  
    18  // POST /create-account
    19  func (a *API) createAccount(ctx context.Context, ins struct {
    20  	RootXPubs []chainkd.XPub `json:"root_xpubs"`
    21  	Quorum    int            `json:"quorum"`
    22  	Alias     string         `json:"alias"`
    23  }) Response {
    24  	acc, err := a.wallet.AccountMgr.Create(ins.RootXPubs, ins.Quorum, ins.Alias, signers.BIP0044)
    25  	if err != nil {
    26  		return NewErrorResponse(err)
    27  	}
    28  
    29  	annotatedAccount := account.Annotated(acc)
    30  	log.WithField("account ID", annotatedAccount.ID).Info("Created account")
    31  
    32  	return NewSuccessResponse(annotatedAccount)
    33  }
    34  
    35  // POST update-account-alias
    36  func (a *API) updateAccountAlias(ctx context.Context, ins struct {
    37  	AccountID    string `json:"account_id"`
    38  	AccountAlias string `json:"account_alias"`
    39  	NewAlias     string `json:"new_alias"`
    40  }) Response {
    41  	accountID := ins.AccountID
    42  	if ins.AccountAlias != "" {
    43  		foundAccount, err := a.wallet.AccountMgr.FindByAlias(ins.AccountAlias)
    44  		if err != nil {
    45  			return NewErrorResponse(err)
    46  		}
    47  		accountID = foundAccount.ID
    48  	}
    49  	if err := a.wallet.UpdateAccountAlias(accountID, ins.NewAlias); err != nil {
    50  		return NewErrorResponse(err)
    51  	}
    52  	return NewSuccessResponse(nil)
    53  }
    54  
    55  // AccountInfo is request struct for deleteAccount
    56  type AccountInfo struct {
    57  	Info string `json:"account_info"`
    58  }
    59  
    60  // POST /delete-account
    61  func (a *API) deleteAccount(ctx context.Context, filter struct {
    62  	AccountID    string `json:"account_id"`
    63  	AccountAlias string `json:"account_alias"`
    64  }) Response {
    65  	accountID := filter.AccountID
    66  	if filter.AccountAlias != "" {
    67  		acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
    68  		if err != nil {
    69  			return NewErrorResponse(err)
    70  		}
    71  		accountID = acc.ID
    72  	}
    73  	if err := a.wallet.DeleteAccount(accountID); err != nil {
    74  		return NewErrorResponse(err)
    75  	}
    76  
    77  	return NewSuccessResponse(nil)
    78  }
    79  
    80  type validateAddressResp struct {
    81  	Valid   bool `json:"valid"`
    82  	IsLocal bool `json:"is_local"`
    83  }
    84  
    85  // POST /validate-address
    86  func (a *API) validateAddress(ctx context.Context, ins struct {
    87  	Address string `json:"address"`
    88  }) Response {
    89  	resp := &validateAddressResp{
    90  		Valid:   false,
    91  		IsLocal: false,
    92  	}
    93  	address, err := common.DecodeAddress(ins.Address, &consensus.ActiveNetParams)
    94  	if err != nil {
    95  		return NewSuccessResponse(resp)
    96  	}
    97  
    98  	redeemContract := address.ScriptAddress()
    99  	program := []byte{}
   100  	switch address.(type) {
   101  	case *common.AddressWitnessPubKeyHash:
   102  		program, err = vmutil.P2WPKHProgram(redeemContract)
   103  	case *common.AddressWitnessScriptHash:
   104  		program, err = vmutil.P2WSHProgram(redeemContract)
   105  	default:
   106  		return NewSuccessResponse(resp)
   107  	}
   108  	if err != nil {
   109  		return NewSuccessResponse(resp)
   110  	}
   111  
   112  	resp.Valid = true
   113  	resp.IsLocal = a.wallet.AccountMgr.IsLocalControlProgram(program)
   114  	return NewSuccessResponse(resp)
   115  }
   116  
   117  type addressResp struct {
   118  	AccountAlias   string `json:"account_alias"`
   119  	AccountID      string `json:"account_id"`
   120  	Address        string `json:"address"`
   121  	ControlProgram string `json:"control_program"`
   122  	Change         bool   `json:"change"`
   123  	KeyIndex       uint64 `json:"key_index"`
   124  }
   125  
   126  // SortByIndex implements sort.Interface for addressResp slices
   127  type SortByIndex []addressResp
   128  
   129  func (a SortByIndex) Len() int           { return len(a) }
   130  func (a SortByIndex) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   131  func (a SortByIndex) Less(i, j int) bool { return a[i].KeyIndex < a[j].KeyIndex }
   132  
   133  func (a *API) listAddresses(ctx context.Context, ins struct {
   134  	AccountID    string `json:"account_id"`
   135  	AccountAlias string `json:"account_alias"`
   136  	From         uint   `json:"from"`
   137  	Count        uint   `json:"count"`
   138  }) Response {
   139  	accountID := ins.AccountID
   140  	var target *account.Account
   141  	if ins.AccountAlias != "" {
   142  		acc, err := a.wallet.AccountMgr.FindByAlias(ins.AccountAlias)
   143  		if err != nil {
   144  			return NewErrorResponse(err)
   145  		}
   146  		target = acc
   147  	} else {
   148  		acc, err := a.wallet.AccountMgr.FindByID(accountID)
   149  		if err != nil {
   150  			return NewErrorResponse(err)
   151  		}
   152  		target = acc
   153  	}
   154  
   155  	cps, err := a.wallet.AccountMgr.ListControlProgram()
   156  	if err != nil {
   157  		return NewErrorResponse(err)
   158  	}
   159  
   160  	addresses := []addressResp{}
   161  	for _, cp := range cps {
   162  		if cp.Address == "" || cp.AccountID != target.ID {
   163  			continue
   164  		}
   165  		addresses = append(addresses, addressResp{
   166  			AccountAlias:   target.Alias,
   167  			AccountID:      cp.AccountID,
   168  			Address:        cp.Address,
   169  			ControlProgram: hex.EncodeToString(cp.ControlProgram),
   170  			Change:         cp.Change,
   171  			KeyIndex:       cp.KeyIndex,
   172  		})
   173  	}
   174  
   175  	// sort AddressResp by KeyIndex
   176  	sort.Sort(SortByIndex(addresses))
   177  	start, end := getPageRange(len(addresses), ins.From, ins.Count)
   178  	return NewSuccessResponse(addresses[start:end])
   179  }
   180  
   181  type minigAddressResp struct {
   182  	MiningAddress string `json:"mining_address"`
   183  }
   184  
   185  func (a *API) getMiningAddress(ctx context.Context) Response {
   186  	miningAddress, err := a.wallet.AccountMgr.GetMiningAddress()
   187  	if err != nil {
   188  		return NewErrorResponse(err)
   189  	}
   190  	return NewSuccessResponse(minigAddressResp{
   191  		MiningAddress: miningAddress,
   192  	})
   193  }
   194  
   195  // POST /set-mining-address
   196  func (a *API) setMiningAddress(ctx context.Context, in struct {
   197  	MiningAddress string `json:"mining_address"`
   198  }) Response {
   199  	miningAddress, err := a.wallet.AccountMgr.SetMiningAddress(in.MiningAddress)
   200  	if err != nil {
   201  		return NewErrorResponse(err)
   202  	}
   203  	return NewSuccessResponse(minigAddressResp{
   204  		MiningAddress: miningAddress,
   205  	})
   206  }