OSDN Git Service

api add createAccount and createKey (#393)
authorwyjDoraemon <46176410+wyjDoraemon@users.noreply.github.com>
Tue, 3 Sep 2019 03:05:46 +0000 (11:05 +0800)
committerPaladz <yzhu101@uottawa.ca>
Tue, 3 Sep 2019 03:05:46 +0000 (11:05 +0800)
* api add createAccount and createKey

* skip ci test and reuse data structure

* add api ...

* fix

* fix

* fix createAccount alias

* fix apinode

api/accounts.go
api/hsm.go
api/query.go
api/receivers.go
toolbar/apinode/account.go [new file with mode: 0644]
toolbar/apinode/account_test.go [new file with mode: 0644]
toolbar/apinode/node.go
toolbar/apinode/query.go [new file with mode: 0644]
toolbar/apinode/query_test.go [new file with mode: 0644]

index a0d551a..b75aa51 100644 (file)
@@ -15,12 +15,14 @@ import (
        "github.com/vapor/protocol/vm/vmutil"
 )
 
-// POST /create-account
-func (a *API) createAccount(ctx context.Context, ins struct {
+type CreateAccountReq struct {
        RootXPubs []chainkd.XPub `json:"root_xpubs"`
        Quorum    int            `json:"quorum"`
        Alias     string         `json:"alias"`
-}) Response {
+}
+
+// POST /create-account
+func (a *API) createAccount(ctx context.Context, ins CreateAccountReq) Response {
        acc, err := a.wallet.AccountMgr.Create(ins.RootXPubs, ins.Quorum, ins.Alias, signers.BIP0044)
        if err != nil {
                return NewErrorResponse(err)
@@ -58,10 +60,7 @@ type AccountInfo struct {
 }
 
 // POST /delete-account
-func (a *API) deleteAccount(ctx context.Context, filter struct {
-       AccountID    string `json:"account_id"`
-       AccountAlias string `json:"account_alias"`
-}) Response {
+func (a *API) deleteAccount(ctx context.Context, filter AccountFilter) Response {
        accountID := filter.AccountID
        if filter.AccountAlias != "" {
                acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
@@ -114,7 +113,14 @@ func (a *API) validateAddress(ctx context.Context, ins struct {
        return NewSuccessResponse(resp)
 }
 
-type addressResp struct {
+type AddressReq struct {
+       AccountID    string `json:"account_id"`
+       AccountAlias string `json:"account_alias"`
+       From         uint   `json:"from"`
+       Count        uint   `json:"count"`
+}
+
+type AddressResp struct {
        AccountAlias   string `json:"account_alias"`
        AccountID      string `json:"account_id"`
        Address        string `json:"address"`
@@ -124,18 +130,13 @@ type addressResp struct {
 }
 
 // SortByIndex implements sort.Interface for addressResp slices
-type SortByIndex []addressResp
+type SortByIndex []AddressResp
 
 func (a SortByIndex) Len() int           { return len(a) }
 func (a SortByIndex) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
 func (a SortByIndex) Less(i, j int) bool { return a[i].KeyIndex < a[j].KeyIndex }
 
-func (a *API) listAddresses(ctx context.Context, ins struct {
-       AccountID    string `json:"account_id"`
-       AccountAlias string `json:"account_alias"`
-       From         uint   `json:"from"`
-       Count        uint   `json:"count"`
-}) Response {
+func (a *API) listAddresses(ctx context.Context, ins AddressReq) Response {
        accountID := ins.AccountID
        var target *account.Account
        if ins.AccountAlias != "" {
@@ -157,12 +158,12 @@ func (a *API) listAddresses(ctx context.Context, ins struct {
                return NewErrorResponse(err)
        }
 
-       addresses := []addressResp{}
+       addresses := []AddressResp{}
        for _, cp := range cps {
                if cp.Address == "" || cp.AccountID != target.ID {
                        continue
                }
-               addresses = append(addresses, addressResp{
+               addresses = append(addresses, AddressResp{
                        AccountAlias:   target.Alias,
                        AccountID:      cp.AccountID,
                        Address:        cp.Address,
index fb2b4e6..3158c20 100644 (file)
@@ -9,19 +9,21 @@ import (
        "github.com/vapor/crypto/ed25519/chainkd"
 )
 
-type createKeyResp struct {
+type CreateKeyReq struct {
+       Alias    string `json:"alias"`
+       Password string `json:"password"`
+       Mnemonic string `json:"mnemonic"`
+       Language string `json:"language"`
+}
+
+type CreateKeyResp struct {
        Alias    string       `json:"alias"`
        XPub     chainkd.XPub `json:"xpub"`
        File     string       `json:"file"`
        Mnemonic string       `json:"mnemonic,omitempty"`
 }
 
-func (a *API) pseudohsmCreateKey(ctx context.Context, in struct {
-       Alias    string `json:"alias"`
-       Password string `json:"password"`
-       Mnemonic string `json:"mnemonic"`
-       Language string `json:"language"`
-}) Response {
+func (a *API) pseudohsmCreateKey(ctx context.Context, in CreateKeyReq) Response {
        if in.Language == "" {
                in.Language = "en"
        }
@@ -30,13 +32,13 @@ func (a *API) pseudohsmCreateKey(ctx context.Context, in struct {
                if err != nil {
                        return NewErrorResponse(err)
                }
-               return NewSuccessResponse(&createKeyResp{Alias: xpub.Alias, XPub: xpub.XPub, File: xpub.File})
+               return NewSuccessResponse(&CreateKeyResp{Alias: xpub.Alias, XPub: xpub.XPub, File: xpub.File})
        }
        xpub, mnemonic, err := a.wallet.Hsm.XCreate(in.Alias, in.Password, in.Language)
        if err != nil {
                return NewErrorResponse(err)
        }
-       return NewSuccessResponse(&createKeyResp{Alias: xpub.Alias, XPub: xpub.XPub, File: xpub.File, Mnemonic: *mnemonic})
+       return NewSuccessResponse(&CreateKeyResp{Alias: xpub.Alias, XPub: xpub.XPub, File: xpub.File, Mnemonic: *mnemonic})
 }
 
 func (a *API) pseudohsmUpdateKeyAlias(ctx context.Context, in struct {
index d65acaa..fba82b8 100644 (file)
@@ -283,8 +283,7 @@ func (a *API) decodeRawTransaction(ctx context.Context, ins struct {
        return NewSuccessResponse(tx)
 }
 
-// POST /list-unspent-outputs
-func (a *API) listUnspentOutputs(ctx context.Context, filter struct {
+type ListUtxosReq struct {
        AccountID     string `json:"account_id"`
        AccountAlias  string `json:"account_alias"`
        ID            string `json:"id"`
@@ -292,7 +291,10 @@ func (a *API) listUnspentOutputs(ctx context.Context, filter struct {
        SmartContract bool   `json:"smart_contract"`
        From          uint   `json:"from"`
        Count         uint   `json:"count"`
-}) Response {
+}
+
+// POST /list-unspent-outputs
+func (a *API) listUnspentOutputs(ctx context.Context, filter ListUtxosReq) Response {
        accountID := filter.AccountID
        if filter.AccountAlias != "" {
                acc, err := a.wallet.AccountMgr.FindByAlias(filter.AccountAlias)
index 02d80b9..28564da 100644 (file)
@@ -6,10 +6,12 @@ import (
        "github.com/vapor/blockchain/txbuilder"
 )
 
-func (a *API) createAccountReceiver(ctx context.Context, ins struct {
+type AccountFilter struct {
        AccountID    string `json:"account_id"`
        AccountAlias string `json:"account_alias"`
-}) Response {
+}
+
+func (a *API) createAccountReceiver(ctx context.Context, ins AccountFilter) Response {
        accountID := ins.AccountID
        if ins.AccountAlias != "" {
                account, err := a.wallet.AccountMgr.FindByAlias(ins.AccountAlias)
diff --git a/toolbar/apinode/account.go b/toolbar/apinode/account.go
new file mode 100644 (file)
index 0000000..818f7ee
--- /dev/null
@@ -0,0 +1,95 @@
+package apinode
+
+import (
+       "encoding/json"
+
+       "github.com/vapor/api"
+       "github.com/vapor/blockchain/pseudohsm"
+       "github.com/vapor/blockchain/query"
+       "github.com/vapor/blockchain/txbuilder"
+       "github.com/vapor/crypto/ed25519/chainkd"
+       "github.com/vapor/errors"
+)
+
+func (n *Node) CreateKey(alias, password string) (*api.CreateKeyResp, error) {
+       url := "/create-key"
+       payload, err := json.Marshal(api.CreateKeyReq{Alias: alias, Password: password})
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &api.CreateKeyResp{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) ListKeys() (*[]pseudohsm.XPub, error) {
+       url := "/list-keys"
+       res := &[]pseudohsm.XPub{}
+       return res, n.request(url, nil, res)
+}
+
+//默认创建单签账户
+func (n *Node) CreateAccount(keyAlias, accountAlias string) (*query.AnnotatedAccount, error) {
+       xPub, err := n.ListKeys()
+       if err != nil {
+               return nil, err
+       }
+
+       var rootXPub *chainkd.XPub
+       for _, x := range *xPub {
+               if x.Alias == keyAlias {
+                       rootXPub = &x.XPub
+                       break
+               }
+       }
+
+       if rootXPub == nil {
+               return nil, errors.New("keyAlias not found!")
+       }
+
+       return n.postCreateAccount(accountAlias, 1, []chainkd.XPub{*rootXPub})
+}
+
+//多签账户
+func (n *Node) CreateMultiSignAccount(alias string, quorum int, rootXPubs []chainkd.XPub) (*query.AnnotatedAccount, error) {
+       return n.postCreateAccount(alias, quorum, rootXPubs)
+}
+
+func (n *Node) postCreateAccount(alias string, quorum int, rootXPubs []chainkd.XPub) (*query.AnnotatedAccount, error) {
+       url := "/create-account"
+       payload, err := json.Marshal(api.CreateAccountReq{
+               Alias:     alias,
+               Quorum:    quorum,
+               RootXPubs: rootXPubs,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &query.AnnotatedAccount{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) ListAccounts() (*[]query.AnnotatedAccount, error) {
+       url := "/list-accounts"
+       payload, err := json.Marshal(struct{}{})
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &[]query.AnnotatedAccount{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) CreateAccountReceiver(alias string) (*txbuilder.Receiver, error) {
+       url := "/create-account-receiver"
+       payload, err := json.Marshal(api.AccountFilter{
+               AccountAlias: alias,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &txbuilder.Receiver{}
+       return res, n.request(url, payload, res)
+}
diff --git a/toolbar/apinode/account_test.go b/toolbar/apinode/account_test.go
new file mode 100644 (file)
index 0000000..df52118
--- /dev/null
@@ -0,0 +1,51 @@
+//+build apinode
+
+package apinode
+
+import (
+       "fmt"
+       "testing"
+)
+
+var n *Node
+
+func TestMain(m *testing.M) {
+       n = NewNode("http://127.0.0.1:9889")
+       m.Run()
+}
+
+func TestNodeCreateKey(t *testing.T) {
+       res, err := n.CreateKey("test10", "123456")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       fmt.Println(res)
+}
+
+func TestNodeCreateAccount(t *testing.T) {
+       res, err := n.CreateAccount("test10", "test11")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       fmt.Println(res)
+}
+
+func TestNodeCreateAccountReceiver(t *testing.T) {
+       res, err := n.CreateAccountReceiver("test10")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       fmt.Println(res)
+}
+
+func TestNodeListAccounts(t *testing.T) {
+       res, err := n.ListAccounts()
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       fmt.Println(res)
+}
index a056723..d15c068 100644 (file)
@@ -4,6 +4,7 @@ import (
        "encoding/json"
 
        "github.com/vapor/errors"
+       "github.com/vapor/netsync/peers"
        "github.com/vapor/toolbar/common"
 )
 
@@ -33,5 +34,41 @@ func (n *Node) request(path string, payload []byte, respData interface{}) error
                return errors.New(resp.ErrDetail)
        }
 
+       if resp.Data == nil {
+               return nil
+       }
+
        return json.Unmarshal(resp.Data, respData)
 }
+
+func (n *Node) DisconnectPeer(peerID string) error {
+       url := "/disconnect-peer"
+       payload, err := json.Marshal(struct {
+               PeerID string `json:"peer_id"`
+       }{
+               PeerID: peerID,
+       })
+       if err != nil {
+               return err
+       }
+
+       return n.request(url, payload, nil)
+
+}
+
+func (n *Node) ConnectPeer(ip string, port uint16) (*peers.Peer, error) {
+       url := "/connect-peer"
+       payload, err := json.Marshal(struct {
+               Ip   string `json:"ip"`
+               Port uint16 `json:"port"`
+       }{
+               Ip:   ip,
+               Port: port,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &peers.Peer{}
+       return res, n.request(url, payload, res)
+}
diff --git a/toolbar/apinode/query.go b/toolbar/apinode/query.go
new file mode 100644 (file)
index 0000000..9486a09
--- /dev/null
@@ -0,0 +1,72 @@
+package apinode
+
+import (
+       "encoding/json"
+
+       "github.com/vapor/api"
+       "github.com/vapor/blockchain/query"
+       "github.com/vapor/errors"
+       "github.com/vapor/netsync/peers"
+       "github.com/vapor/wallet"
+)
+
+func (n *Node) ListAddresses(accountAlias string, from, count uint) (*[]api.AddressResp, error) {
+       url := "/list-addresses"
+       payload, err := json.Marshal(api.AddressReq{
+               AccountAlias: accountAlias,
+               From:         from,
+               Count:        count,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &[]api.AddressResp{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) ListBalances(accountAlias string) (*[]wallet.AccountBalance, error) {
+       url := "/list-balances"
+       payload, err := json.Marshal(api.AccountFilter{
+               AccountAlias: accountAlias,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &[]wallet.AccountBalance{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) ListUtxos(accountAlias string,from, count uint) (*[]query.AnnotatedUTXO, error) {
+       url := "/list-unspent-outputs"
+       payload, err := json.Marshal(api.ListUtxosReq{
+               AccountAlias:  accountAlias,
+               From:          from,
+               Count:         count,
+       })
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       res := &[]query.AnnotatedUTXO{}
+       return res, n.request(url, payload, res)
+}
+
+func (n *Node) WalletInfo() (*api.WalletInfo, error) {
+       url := "/wallet-info"
+       res := &api.WalletInfo{}
+       return res, n.request(url, nil, res)
+}
+
+func (n *Node) NetInfo() (*api.NetInfo, error) {
+       url := "/net-info"
+       res := &api.NetInfo{}
+       return res, n.request(url, nil, res)
+}
+
+func (n *Node) ListPeers() (*[]*peers.PeerInfo, error) {
+       url := "/list-peers"
+       res := &[]*peers.PeerInfo{}
+       return res, n.request(url, nil, res)
+}
diff --git a/toolbar/apinode/query_test.go b/toolbar/apinode/query_test.go
new file mode 100644 (file)
index 0000000..bf21031
--- /dev/null
@@ -0,0 +1,56 @@
+//+build apinode
+
+package apinode
+
+import (
+       "fmt"
+       "testing"
+)
+
+func TestNodeListAddresses(t *testing.T) {
+       res, err := n.ListAddresses("test10", 0, 10)
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}
+
+func TestNodeListBalances(t *testing.T) {
+       res, err := n.ListBalances("test10")
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}
+
+func TestNodeListUtxos(t *testing.T) {
+       res, err := n.ListUtxos("test10", 0, 10)
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}
+
+func TestNodeWalletInfo(t *testing.T) {
+       res, err := n.WalletInfo()
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}
+
+func TestNodeNetInfo(t *testing.T) {
+       res, err := n.NetInfo()
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}
+
+func TestNodeListPeers(t *testing.T) {
+       res, err := n.ListPeers()
+       if err != nil {
+               t.Fatal(err)
+       }
+       fmt.Println(res)
+}