From: zhouyasong Date: Tue, 19 Sep 2017 10:16:46 +0000 (+0800) Subject: add accesstoken X-Git-Tag: v1.0.5~506^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=ef45a05541fd333db531de006179ce9766ae49e8;p=bytom%2Fbytom.git add accesstoken --- diff --git a/blockchain/accesstoken/accesstoken.go b/blockchain/accesstoken/accesstoken.go new file mode 100644 index 00000000..80394235 --- /dev/null +++ b/blockchain/accesstoken/accesstoken.go @@ -0,0 +1,175 @@ +// Package accesstoken provides storage and validation of Chain Core +// credentials. +package accesstoken + +// TODO(tessr): merge this package into chain/net/http/authn + +import ( + "context" + "crypto/rand" + // "database/sql" + "fmt" + "regexp" + "time" + + "github.com/bytom/crypto/sha3pool" + // "chain/database/pg" + "github.com/bytom/errors" +) + +const ( + tokenSize = 32 + defaultLimit = 100 +) + +var ( + // ErrBadID is returned when Create is called on an invalid id string. + ErrBadID = errors.New("invalid id") + // ErrDuplicateID is returned when Create is called on an existing ID. + ErrDuplicateID = errors.New("duplicate access token ID") + // ErrBadType is returned when Create is called with a bad type. + ErrBadType = errors.New("type must be client or network") + + // validIDRegexp checks that all characters are alphumeric, _ or -. + // It also must have a length of at least 1. + validIDRegexp = regexp.MustCompile(`^[\w-]+$`) +) + +type Token struct { + ID string `json:"id"` + Token string `json:"token,omitempty"` + Type string `json:"type,omitempty"` // deprecated in 1.2 + Created time.Time `json:"created_at"` + sortID string +} + +type CredentialStore struct { + // DB pg.DB +} + +// Create generates a new access token with the given ID. +func (cs *Token) Create(ctx context.Context, id, typ string) (*Token, error) { + if !validIDRegexp.MatchString(id) { + return nil, errors.WithDetailf(ErrBadID, "invalid id %q", id) + } + + var secret [tokenSize]byte + _, err := rand.Read(secret[:]) + if err != nil { + return nil, err + } + var hashedSecret [32]byte + sha3pool.Sum256(hashedSecret[:], secret[:]) + + /* const q = ` + INSERT INTO access_tokens (id, type, hashed_secret) + VALUES($1, $2, $3) + RETURNING created, sort_id + ` + */var ( + created time.Time + sortID string + // maybeType = sql.NullString{String: typ, Valid: typ != ""} + ) + /* err = cs.DB.QueryRowContext(ctx, q, id, maybeType, hashedSecret[:]).Scan(&created, &sortID) + if pg.IsUniqueViolation(err) { + return nil, errors.WithDetailf(ErrDuplicateID, "id %q already in use", id) + } + if err != nil { + return nil, errors.Wrap(err) + } + */ + return &Token{ + ID: id, + Token: fmt.Sprintf("%s:%x", id, secret), + Type: typ, + Created: created, + sortID: sortID, + }, nil +} + +// Check returns whether or not an id-secret pair is a valid access token. +func (cs *Token) Check(ctx context.Context, id string, secret []byte) (bool, error) { + var ( + toHash [tokenSize]byte + hashed [32]byte + ) + copy(toHash[:], secret) + sha3pool.Sum256(hashed[:], toHash[:]) + + /*const q = `SELECT EXISTS(SELECT 1 FROM access_tokens WHERE id=$1 AND hashed_secret=$2)` + var valid bool + err := cs.DB.QueryRowContext(ctx, q, id, hashed[:]).Scan(&valid) + if err != nil { + return false, err + } + */ + // return valid, nil + return true, nil +} + +// Exists returns whether an id is part of a valid access token. It does not validate a secret. +func (cs *Token) Exists(ctx context.Context, id string) bool { + /* const q = `SELECT EXISTS(SELECT 1 FROM access_tokens WHERE id=$1)` + var valid bool + err := cs.DB.QueryRowContext(ctx, q, id).Scan(&valid) + if err != nil { + return false + } + return valid + */ + return true +} + +// List lists all access tokens. +func (cs *Token) List(ctx context.Context, typ, after string, limit int) ([]*Token, string, error) { + if limit == 0 { + limit = defaultLimit + } + /* const q = ` + SELECT id, type, sort_id, created FROM access_tokens + WHERE ($1='' OR type=$1::access_token_type) AND ($2='' OR sort_id<$2) + ORDER BY sort_id DESC + LIMIT $3 + ` + var tokens []*Token + // err := pg.ForQueryRows(ctx, cs.DB, q, typ, after, limit, func(id string, maybeType sql.NullString, sortID string, created time.Time) { + t := Token{ + ID: id, + Created: created, + Type: maybeType.String, + sortID: sortID, + } + tokens = append(tokens, &t) + }) + if err != nil { + return nil, "", errors.Wrap(err) + } + */ + var tokens []*Token + var next string + if len(tokens) > 0 { + next = tokens[len(tokens)-1].sortID + } + + return tokens, next, nil +} + +// Delete deletes an access token by id. +func (cs *Token) Delete(ctx context.Context, id string) error { + /* const q = `DELETE FROM access_tokens WHERE id=$1` + res, err := cs.DB.ExecContext(ctx, q, id) + if err != nil { + return errors.Wrap(err) + } + */ + /* deleted, err := res.RowsAffected() + if err != nil { + return errors.Wrap(err) + } + + if deleted == 0 { + return errors.WithDetailf(pg.ErrUserInputNotFound, "acccess token id %s", id) + } + */return nil +} diff --git a/blockchain/accesstokens.go b/blockchain/accesstokens.go new file mode 100644 index 00000000..733158e3 --- /dev/null +++ b/blockchain/accesstokens.go @@ -0,0 +1,116 @@ +package blockchain + +import ( + "context" + "encoding/json" + + "github.com/bytom/blockchain/accesstoken" + "github.com/bytom/errors" + "github.com/bytom/log" + // "github.com/bytom/net/http/authz" + "github.com/bytom/net/http/httpjson" +) + +/* +const ( + defGenericPageSize = 100 +) +*/ +var errCurrentToken = errors.New("token cannot delete itself") + +func (bcr *BlockchainReactor) createAccessToken(ctx context.Context, x struct{ ID, Type string }) (*accesstoken.Token, error) { + token, err := bcr.accesstoken.Create(ctx, x.ID, x.Type) + if err != nil { + return nil, errors.Wrap(err) + } + + log.Printf(ctx, "-------createAccessToken-------") + + if x.Type == "" { + return token, nil + } + + data := map[string]interface{}{ + "id": token.ID, + } + _, err = json.Marshal(data) + // guardData, err := json.Marshal(data) + if err != nil { + return nil, errors.Wrap(err) + } + /* + var grant *authz.Grant + + // Type is deprecated; however, for backward compatibility, using the + // Type field will create a grant associated with this new token. + switch x.Type { + case "client": + grant = &authz.Grant{ + GuardType: "access_token", + GuardData: guardData, + Policy: "client-readwrite", + } + case "network": + grant = &authz.Grant{ + GuardType: "access_token", + GuardData: guardData, + Policy: "crosscore", + } + default: + // We've already returned if x.Type wasn't specified, so this must be a bad type. + return nil, accesstoken.ErrBadType + } + err = a.sdb.Exec(ctx, a.grants.Save(ctx, grant)) + if err != nil { + return nil, errors.Wrap(err) + } + */ + token.Type = x.Type // deprecated + + return token, nil +} + +func (bcr *BlockchainReactor) listAccessTokens(ctx context.Context, x requestQuery) (*page, error) { + limit := x.PageSize + if limit == 0 { + limit = 100 + } + + tokens, next, err := bcr.accesstoken.List(ctx, x.Type, x.After, limit) + if err != nil { + return nil, err + } + + log.Printf(ctx, "--------listAccessTokens-------") + + outQuery := x + outQuery.After = next + + return &page{ + Items: httpjson.Array(tokens), + LastPage: len(tokens) < limit, + Next: outQuery, + }, nil +} + +func (bcr *BlockchainReactor) deleteAccessToken(ctx context.Context, x struct{ ID string }) error { + currentID, _, _ := httpjson.Request(ctx).BasicAuth() + if currentID == x.ID { + return errCurrentToken + } + err := bcr.accesstoken.Delete(ctx, x.ID) + if err != nil { + return err + } + + log.Printf(ctx, "-------deleteAccessToken-------") + + /* err = a.sdb.Exec(ctx, a.deleteGrantsByAccessToken(x.ID)) + if err != nil { + // well, technically we did delete the access token, so don't return the error + // TODO(tessr): make this whole operation atomic, such that we either delete + // both the access token and its grants, or we return a failure. + log.Printkv(ctx, log.KeyError, err, "at", "revoking grants for access token", "token", x.ID) + } + */return nil +} diff --git a/blockchain/reactor.go b/blockchain/reactor.go index a47ddcae..54a79541 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -3,31 +3,31 @@ package blockchain import ( "bytes" "context" - "reflect" - "time" - "net/http" "fmt" + "net/http" + "reflect" + "time" - wire "github.com/tendermint/go-wire" - "github.com/bytom/p2p" - "github.com/bytom/types" - "github.com/bytom/protocol/bc/legacy" - "github.com/bytom/protocol" - "github.com/bytom/blockchain/query" - "github.com/bytom/encoding/json" - cmn "github.com/tendermint/tmlibs/common" - "github.com/bytom/blockchain/txdb" + "github.com/bytom/blockchain/accesstoken" "github.com/bytom/blockchain/account" "github.com/bytom/blockchain/asset" + "github.com/bytom/blockchain/txdb" "github.com/bytom/blockchain/txfeed" + "github.com/bytom/encoding/json" "github.com/bytom/log" + "github.com/bytom/p2p" + "github.com/bytom/protocol" + "github.com/bytom/protocol/bc/legacy" + "github.com/bytom/types" + wire "github.com/tendermint/go-wire" + cmn "github.com/tendermint/tmlibs/common" //"github.com/bytom/net/http/gzip" "github.com/bytom/net/http/httpjson" //"github.com/bytom/net/http/limit" - "github.com/bytom/net/http/static" - "github.com/bytom/generated/dashboard" - "github.com/bytom/errors" "github.com/bytom/blockchain/txbuilder" + "github.com/bytom/errors" + "github.com/bytom/generated/dashboard" + "github.com/bytom/net/http/static" ) const ( @@ -46,26 +46,26 @@ const ( // check if we should switch to consensus reactor switchToConsensusIntervalSeconds = 1 maxBlockchainResponseSize = 22020096 + 2 - crosscoreRPCPrefix = "/rpc/" + crosscoreRPCPrefix = "/rpc/" ) // BlockchainReactor handles long-term catchup syncing. type BlockchainReactor struct { p2p.BaseReactor - chain *protocol.Chain - store *txdb.Store - accounts *account.Manager - assets *asset.Registry - txFeeds *txfeed.TxFeed - indexer *query.Indexer - pool *BlockPool - mux *http.ServeMux - handler http.Handler - fastSync bool - requestsCh chan BlockRequest - timeoutsCh chan string - submitter txbuilder.Submitter + chain *protocol.Chain + store *txdb.Store + accounts *account.Manager + assets *asset.Registry + txFeeds *txfeed.TxFeed + pool *BlockPool + mux *http.ServeMux + accesstoken *accesstoken.Token + handler http.Handler + fastSync bool + requestsCh chan BlockRequest + timeoutsCh chan string + submitter txbuilder.Submitter evsw types.EventSwitch } @@ -94,7 +94,7 @@ func batchRecover(ctx context.Context, v *interface{}) { } func jsonHandler(f interface{}) http.Handler { - h, err := httpjson.Handler(f, errorFormatter.Write) + h, err := httpjson.Handler(f, errorFormatter.Write) if err != nil { panic(err) } @@ -106,12 +106,12 @@ func alwaysError(err error) http.Handler { } func (bcr *BlockchainReactor) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - bcr.handler.ServeHTTP(rw, req) + bcr.handler.ServeHTTP(rw, req) } func (bcr *BlockchainReactor) info(ctx context.Context) (map[string]interface{}, error) { - //if a.config == nil { - // never configured + //if a.config == nil { + // never configured log.Printf(ctx, "-------info-----") return map[string]interface{}{ "is_configured": false, @@ -124,7 +124,7 @@ func (bcr *BlockchainReactor) info(ctx context.Context) (map[string]interface{}, } func (bcr *BlockchainReactor) createblockkey(ctx context.Context) { - log.Printf(ctx,"creat-block-key") + log.Printf(ctx, "creat-block-key") } func webAssetsHandler(next http.Handler) http.Handler { @@ -138,7 +138,7 @@ func webAssetsHandler(next http.Handler) http.Handler { } func maxBytes(h http.Handler) http.Handler { - const maxReqSize = 1e7 // 10MB + const maxReqSize = 1e7 // 10MB return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // A block can easily be bigger than maxReqSize, but everything // else should be pretty small. @@ -153,44 +153,41 @@ func (bcr *BlockchainReactor) BuildHander() { m := bcr.mux m.Handle("/create-account", jsonHandler(bcr.createAccount)) m.Handle("/create-asset", jsonHandler(bcr.createAsset)) - m.Handle("/update-account-tags",jsonHandler(bcr.updateAccountTags)) - m.Handle("/update-asset-tags",jsonHandler(bcr.updateAssetTags)) + m.Handle("/update-account-tags", jsonHandler(bcr.updateAccountTags)) + m.Handle("/update-asset-tags", jsonHandler(bcr.updateAssetTags)) m.Handle("/build-transaction", jsonHandler(bcr.build)) - m.Handle("/create-control-program",jsonHandler(bcr.createControlProgram)) + m.Handle("/create-control-program", jsonHandler(bcr.createControlProgram)) m.Handle("/create-account-receiver", jsonHandler(bcr.createAccountReceiver)) m.Handle("/create-transaction-feed", jsonHandler(bcr.createTxFeed)) m.Handle("/get-transaction-feed", jsonHandler(bcr.getTxFeed)) m.Handle("/update-transaction-feed", jsonHandler(bcr.updateTxFeed)) m.Handle("/delete-transaction-feed", jsonHandler(bcr.deleteTxFeed)) - m.Handle("/list-accounts", jsonHandler(bcr.listAccounts)) - m.Handle("/list-assets", jsonHandler(bcr.listAssets)) - m.Handle("/list-transaction-feeds", jsonHandler(bcr.listTxFeeds)) - m.Handle("/list-transactions", jsonHandler(bcr.listTransactions)) - m.Handle("/list-balances", jsonHandler(bcr.listBalances)) - m.Handle("/list-unspent-outputs", jsonHandler(bcr.listUnspentOutputs)) m.Handle("/", alwaysError(errors.New("not Found"))) m.Handle("/info", jsonHandler(bcr.info)) m.Handle("/create-block-key", jsonHandler(bcr.createblockkey)) m.Handle("/submit-transaction", jsonHandler(bcr.submit)) + m.Handle("/create-access-token", jsonHandler(bcr.createAccessToken)) + m.Handle("/list-access-tokens", jsonHandler(bcr.listAccessTokens)) + m.Handle("/delete-access-token", jsonHandler(bcr.deleteAccessToken)) - latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if l := latency(m, req); l != nil { defer l.RecordSince(time.Now()) } m.ServeHTTP(w, req) - }) + }) handler := maxBytes(latencyHandler) // TODO(tessr): consider moving this to non-core specific mux handler = webAssetsHandler(handler) -/* handler = healthHandler(handler) - for _, l := range a.requestLimits { - handler = limit.Handler(handler, alwaysError(errRateLimited), l.perSecond, l.burst, l.key) - } - handler = gzip.Handler{Handler: handler} - handler = coreCounter(handler) - handler = timeoutContextHandler(handler) - if a.config != nil && a.config.BlockchainId != nil { - handler = blockchainIDHandler(handler, a.config.BlockchainId.String()) - } + /* handler = healthHandler(handler) + for _, l := range a.requestLimits { + handler = limit.Handler(handler, alwaysError(errRateLimited), l.perSecond, l.burst, l.key) + } + handler = gzip.Handler{Handler: handler} + handler = coreCounter(handler) + handler = timeoutContextHandler(handler) + if a.config != nil && a.config.BlockchainId != nil { + handler = blockchainIDHandler(handler, a.config.BlockchainId.String()) + } */ bcr.handler = handler } @@ -236,39 +233,39 @@ type page struct { } func NewBlockchainReactor(store *txdb.Store, chain *protocol.Chain, accounts *account.Manager, assets *asset.Registry, fastSync bool) *BlockchainReactor { - requestsCh := make(chan BlockRequest, defaultChannelCapacity) - timeoutsCh := make(chan string, defaultChannelCapacity) - pool := NewBlockPool( - store.Height()+1, - requestsCh, - timeoutsCh, - ) - bcR := &BlockchainReactor { - chain: chain, - store: store, - accounts: accounts, - assets: assets, - pool: pool, - mux: http.NewServeMux(), - fastSync: fastSync, - requestsCh: requestsCh, - timeoutsCh: timeoutsCh, - } - bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR) - return bcR + requestsCh := make(chan BlockRequest, defaultChannelCapacity) + timeoutsCh := make(chan string, defaultChannelCapacity) + pool := NewBlockPool( + store.Height()+1, + requestsCh, + timeoutsCh, + ) + bcR := &BlockchainReactor{ + chain: chain, + store: store, + accounts: accounts, + assets: assets, + pool: pool, + mux: http.NewServeMux(), + fastSync: fastSync, + requestsCh: requestsCh, + timeoutsCh: timeoutsCh, + } + bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR) + return bcR } // OnStart implements BaseService func (bcR *BlockchainReactor) OnStart() error { bcR.BaseReactor.OnStart() bcR.BuildHander() - if bcR.fastSync { - _, err := bcR.pool.Start() - if err != nil { - return err - } - go bcR.poolRoutine() - } + if bcR.fastSync { + _, err := bcR.pool.Start() + if err != nil { + return err + } + go bcR.poolRoutine() + } return nil } @@ -313,7 +310,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src *p2p.Peer, msgBytes []byte) switch msg := msg.(type) { case *bcBlockRequestMessage: // Got a request for a block. Respond with block if we have it. - block, _:= bcR.store.GetBlock(msg.Height) + block, _ := bcR.store.GetBlock(msg.Height) if block != nil { msg := &bcBlockResponseMessage{Block: block} queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}) @@ -340,7 +337,6 @@ func (bcR *BlockchainReactor) Receive(chID byte, src *p2p.Peer, msgBytes []byte) } } - // Handle messages from the poolReactor telling the reactor what to do. // NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down! // (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.) @@ -375,19 +371,19 @@ FOR_LOOP: // ask for status updates go bcR.BroadcastStatusRequest() /*case _ = <-switchToConsensusTicker.C: - height, numPending, _ := bcR.pool.GetStatus() - outbound, inbound, _ := bcR.Switch.NumPeers() - bcR.Logger.Info("Consensus ticker", "numPending", numPending, "total", len(bcR.pool.requesters), - "outbound", outbound, "inbound", inbound) - if bcR.pool.IsCaughtUp() { - bcR.Logger.Info("Time to switch to consensus reactor!", "height", height) - bcR.pool.Stop() - - conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor) - conR.SwitchToConsensus(bcR.state) - - break FOR_LOOP - }*/ + height, numPending, _ := bcR.pool.GetStatus() + outbound, inbound, _ := bcR.Switch.NumPeers() + bcR.Logger.Info("Consensus ticker", "numPending", numPending, "total", len(bcR.pool.requesters), + "outbound", outbound, "inbound", inbound) + if bcR.pool.IsCaughtUp() { + bcR.Logger.Info("Time to switch to consensus reactor!", "height", height) + bcR.pool.Stop() + + conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor) + conR.SwitchToConsensus(bcR.state) + + break FOR_LOOP + }*/ case _ = <-trySyncTicker.C: // chan time // This loop can be slow as long as it's doing syncing work. SYNC_LOOP: @@ -399,8 +395,8 @@ FOR_LOOP: // We need both to sync the first block. break SYNC_LOOP } - bcR.pool.PopRequest() - bcR.store.SaveBlock(first) + bcR.pool.PopRequest() + bcR.store.SaveBlock(first) } continue FOR_LOOP case <-bcR.Quit: @@ -415,7 +411,6 @@ func (bcR *BlockchainReactor) BroadcastStatusRequest() error { return nil } - /* // SetEventSwitch implements events.Eventable func (bcR *BlockchainReactor) SetEventSwitch(evsw types.EventSwitch) { diff --git a/cmd/bytomcli/main.go b/cmd/bytomcli/main.go index 4033c134..59280e1f 100644 --- a/cmd/bytomcli/main.go +++ b/cmd/bytomcli/main.go @@ -3,6 +3,7 @@ package main import ( "bytes" "context" + stdjson "encoding/json" "flag" "fmt" "io" @@ -12,20 +13,19 @@ import ( "path/filepath" "strings" "time" - stdjson "encoding/json" "github.com/bytom/blockchain" -// "chain/core/accesstoken" + // "chain/core/accesstoken" //"github.com/bytom/config" - "github.com/bytom/encoding/json" + "github.com/bytom/blockchain/query" "github.com/bytom/blockchain/rpc" + "github.com/bytom/cmd/bytomcli/example" "github.com/bytom/crypto/ed25519" + "github.com/bytom/crypto/ed25519/chainkd" + "github.com/bytom/encoding/json" "github.com/bytom/env" "github.com/bytom/errors" "github.com/bytom/log" - "github.com/bytom/crypto/ed25519/chainkd" - "github.com/bytom/cmd/bytomcli/example" - "github.com/bytom/blockchain/query" ) // config vars @@ -54,29 +54,33 @@ type grantReq struct { } var commands = map[string]*command{ - "create-block-keypair": {createBlockKeyPair}, - "reset": {reset}, - "grant": {grant}, - "revoke": {revoke}, - "wait": {wait}, - "create-account": {createAccount}, - "update-account-tags": {updateAccountTags}, - "create-asset": {createAsset}, - "update-asset-tags": {updateAssetTags}, - "build-transaction": {buildTransaction}, - "create-control-program": {createControlProgram}, + "create-block-keypair": {createBlockKeyPair}, + "reset": {reset}, + "grant": {grant}, + "revoke": {revoke}, + "wait": {wait}, + "create-account": {createAccount}, + "update-account-tags": {updateAccountTags}, + "create-asset": {createAsset}, + "update-asset-tags": {updateAssetTags}, + "build-transaction": {buildTransaction}, + "create-control-program": {createControlProgram}, "create-account-receiver": {createAccountReceiver}, "create-transaction-feed": {createTxFeed}, "get-transaction-feed": {getTxFeed}, "update-transaction-feed": {updateTxFeed}, - "list-accounts": {listAccounts}, - "list-assets": {listAssets}, - "list-transaction-feeds": {listTxFeeds}, - "list-transactions": {listTransactions}, - "list-balances": {listBalances}, - "list-unspent-outputs": {listUnspentOutputs}, + "list-accounts": {listAccounts}, + "list-assets": {listAssets}, + "list-transaction-feeds": {listTxFeeds}, + "list-transactions": {listTransactions}, + "list-balances": {listBalances}, + "list-unspent-outputs": {listUnspentOutputs}, "delete-transaction-feed": {deleteTxFeed}, - "issue-test": {example.IssueTest}, + "issue-test": {example.IssueTest}, + "spend-test": {example.SpendTest}, + "create-access-token": {createAccessToken}, + "list-access-token": {listAccessTokens}, + "delete-access-token": {deleteAccessToken}, } func main() { @@ -111,7 +115,6 @@ func main() { cmd.f(mustRPCClient(), os.Args[2:]) } - func createBlockKeyPair(client *rpc.Client, args []string) { if len(args) != 0 { fatalln("error: create-block-keypair takes no args") @@ -312,20 +315,20 @@ func createAccount(client *rpc.Client, args []string) { fmt.Printf("xprv:%v\n", xprv) fmt.Printf("xpub:%v\n", xpub) type Ins struct { - RootXPubs []chainkd.XPub `json:"root_xpubs"` - Quorum int - Alias string - Tags map[string]interface{} + RootXPubs []chainkd.XPub `json:"root_xpubs"` + Quorum int + Alias string + Tags map[string]interface{} ClientToken string `json:"client_token"` } var ins Ins ins.RootXPubs = []chainkd.XPub{xpub} ins.Quorum = 1 ins.Alias = "alice" - ins.Tags = map[string]interface{}{"test_tag": "v0",} + ins.Tags = map[string]interface{}{"test_tag": "v0"} ins.ClientToken = args[0] account := make([]query.AnnotatedAccount, 1) - client.Call(context.Background(), "/create-account", &[]Ins{ins,}, &account) + client.Call(context.Background(), "/create-account", &[]Ins{ins}, &account) //dieOnRPCError(err) fmt.Printf("responses:%v\n", account[0]) } @@ -342,10 +345,10 @@ func createAsset(client *rpc.Client, args []string) { fmt.Printf("xprv:%v\n", xprv) fmt.Printf("xpub:%v\n", xpub) type Ins struct { - RootXPubs []chainkd.XPub `json:"root_xpubs"` - Quorum int - Alias string - Tags map[string]interface{} + RootXPubs []chainkd.XPub `json:"root_xpubs"` + Quorum int + Alias string + Tags map[string]interface{} Definition map[string]interface{} ClientToken string `json:"client_token"` } @@ -353,11 +356,11 @@ func createAsset(client *rpc.Client, args []string) { ins.RootXPubs = []chainkd.XPub{xpub} ins.Quorum = 1 ins.Alias = "bob" - ins.Tags = map[string]interface{}{"test_tag": "v0",} + ins.Tags = map[string]interface{}{"test_tag": "v0"} ins.Definition = map[string]interface{}{} ins.ClientToken = args[0] assets := make([]query.AnnotatedAsset, 1) - client.Call(context.Background(), "/create-asset", &[]Ins{ins,}, &assets) + client.Call(context.Background(), "/create-asset", &[]Ins{ins}, &assets) //dieOnRPCError(err) fmt.Printf("responses:%v\n", assets) } @@ -395,23 +398,23 @@ func updateAccountTags(client *rpc.Client, args []string) { fmt.Printf("responses:%v\n", responses) } -func updateAssetTags(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:updateAccountTags not use args") +func updateAssetTags(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:updateAccountTags not use args") } type Ins struct { - ID *string - Alias *string - Tags map[string]interface{} `json:"tags"` + ID *string + Alias *string + Tags map[string]interface{} `json:"tags"` } var ins Ins id := "123456" alias := "asdfg" ins.ID = &id ins.Alias = &alias - ins.Tags = map[string]interface{}{"test_tag": "v0",} + ins.Tags = map[string]interface{}{"test_tag": "v0"} responses := make([]interface{}, 50) - client.Call(context.Background(), "/update-asset-tags", &[]Ins{ins,}, &responses) + client.Call(context.Background(), "/update-asset-tags", &[]Ins{ins}, &responses) fmt.Printf("responses:%v\n", responses) } @@ -421,244 +424,297 @@ func buildTransaction(client *rpc.Client, args []string) { } } -func createControlProgram(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:createControlProgram not use args") - } +func createControlProgram(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:createControlProgram not use args") + } type Ins struct { - Type string - Params stdjson.RawMessage -} + Type string + Params stdjson.RawMessage + } var ins Ins //TODO:undefined arguments to ins - responses := make([]interface{},50) - client.Call(context.Background(),"/create-control-program", &[]Ins{ins,}, &responses) - fmt.Printf("responses:%v\n", responses) + responses := make([]interface{}, 50) + client.Call(context.Background(), "/create-control-program", &[]Ins{ins}, &responses) + fmt.Printf("responses:%v\n", responses) } -func createAccountReceiver(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:createAccountReceiver not use args") - } +func createAccountReceiver(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:createAccountReceiver not use args") + } type Ins struct { - AccountID string `json:"account_id"` - AccountAlias string `json:"account_alias"` - ExpiresAt time.Time `json:"expires_at"` -} + AccountID string `json:"account_id"` + AccountAlias string `json:"account_alias"` + ExpiresAt time.Time `json:"expires_at"` + } var ins Ins //TODO:undefined argument to ExpiresAt ins.AccountID = "123456" ins.AccountAlias = "zxcvbn" - responses := make([]interface{},50) - client.Call(context.Background(),"/create-Account-Receiver", &[]Ins{ins,}, &responses) - fmt.Printf("responses:%v\n", responses) + responses := make([]interface{}, 50) + client.Call(context.Background(), "/create-Account-Receiver", &[]Ins{ins}, &responses) + fmt.Printf("responses:%v\n", responses) } -func createTxFeed(client *rpc.Client, args []string){ - if len(args) != 1{ - fatalln("error:createTxFeed take no arguments") - } +func createTxFeed(client *rpc.Client, args []string) { + if len(args) != 1 { + fatalln("error:createTxFeed take no arguments") + } type In struct { - Alias string - Filter string - ClientToken string `json:"client_token"` -} + Alias string + Filter string + ClientToken string `json:"client_token"` + } var in In in.Alias = "asdfgh" in.Filter = "zxcvbn" in.ClientToken = args[0] - client.Call(context.Background(),"/create-transaction-feed",&[]In{in,},nil) + client.Call(context.Background(), "/create-transaction-feed", &[]In{in}, nil) } -func getTxFeed(client *rpc.Client, args []string){ - if len(args) != 0{ +func getTxFeed(client *rpc.Client, args []string) { + if len(args) != 0 { fatalln("error:getTxFeed not use args") } type In struct { - ID string `json:"id,omitempty"` - Alias string `json:"alias,omitempty"` -} + ID string `json:"id,omitempty"` + Alias string `json:"alias,omitempty"` + } var in In in.Alias = "qwerty" in.ID = "123456" - client.Call(context.Background(),"/get-transaction-feed",&[]In{in,},nil) + client.Call(context.Background(), "/get-transaction-feed", &[]In{in}, nil) } -func updateTxFeed(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:updateTxFeed not use args") - } - type In struct { - ID string `json:"id,omitempty"` - Alias string `json:"alias,omitempty"` -} +func updateTxFeed(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:updateTxFeed not use args") + } + type In struct { + ID string `json:"id,omitempty"` + Alias string `json:"alias,omitempty"` + } var in In in.ID = "123456" in.Alias = "qwerty" - client.Call(context.Background(),"/update-transaction-feed",&[]In{in,},nil) + client.Call(context.Background(), "/update-transaction-feed", &[]In{in}, nil) } -func deleteTxFeed(client *rpc.Client, args []string){ - if len(args) != 0{ +func deleteTxFeed(client *rpc.Client, args []string) { + if len(args) != 0 { fatalln("error:deleteTxFeed not use args") } type In struct { - ID string `json:"id,omitempty"` - Alias string `json:"alias,omitempty"` -} + ID string `json:"id,omitempty"` + Alias string `json:"alias,omitempty"` + } var in In - in.ID = "123456" - in.Alias = "qwerty" - client.Call(context.Background(),"/delete-transaction-feed",&[]In{in,},nil) + in.ID = "123456" + in.Alias = "qwerty" + client.Call(context.Background(), "/delete-transaction-feed", &[]In{in}, nil) } -func listAccounts(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listAccounts not use args") - } +func listAccounts(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listAccounts not use args") + } type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` -} + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-accounts",&[]requestQuery{in,},nil) + client.Call(context.Background(), "/list-accounts", &[]requestQuery{in}, nil) } -func listAssets(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listAssets not use args") - } +func listAssets(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listAssets not use args") + } type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` -} + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-assets",&[]requestQuery{in,},nil) + client.Call(context.Background(), "/list-assets", &[]requestQuery{in}, nil) } -func listTxFeeds(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listTxFeeds not use args") - } +func listTxFeeds(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listTxFeeds not use args") + } type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` -} + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-transactions-feeds",&[]requestQuery{in,},nil) + client.Call(context.Background(), "/list-transactions-feeds", &[]requestQuery{in}, nil) } -func listTransactions(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listTransactions not use args") - } +func listTransactions(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listTransactions not use args") + } type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` -} + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-transactions",&[]requestQuery{in,},nil) -} - -func listBalances(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listBalances not use args") - } -type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` + client.Call(context.Background(), "/list-transactions", &[]requestQuery{in}, nil) } +func listBalances(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listBalances not use args") + } + type requestQuery struct { + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } + var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-balance",&[]requestQuery{in,},nil) -} - -func listUnspentOutputs(client *rpc.Client, args []string){ - if len(args) != 0{ - fatalln("error:listUnspentOutputs not use args") - } -type requestQuery struct { - Filter string `json:"filter,omitempty"` - FilterParams []interface{} `json:"filter_params,omitempty"` - SumBy []string `json:"sum_by,omitempty"` - PageSize int `json:"page_size"` - AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` - Timeout json.Duration `json:"timeout"` - After string `json:"after"` - StartTimeMS uint64 `json:"start_time,omitempty"` - EndTimeMS uint64 `json:"end_time,omitempty"` - TimestampMS uint64 `json:"timestamp,omitempty"` - Type string `json:"type"` - Aliases []string `json:"aliases,omitempty"` + client.Call(context.Background(), "/list-balance", &[]requestQuery{in}, nil) } + +func listUnspentOutputs(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listUnspentOutputs not use args") + } + type requestQuery struct { + Filter string `json:"filter,omitempty"` + FilterParams []interface{} `json:"filter_params,omitempty"` + SumBy []string `json:"sum_by,omitempty"` + PageSize int `json:"page_size"` + AscLongPoll bool `json:"ascending_with_long_poll,omitempty"` + Timeout json.Duration `json:"timeout"` + After string `json:"after"` + StartTimeMS uint64 `json:"start_time,omitempty"` + EndTimeMS uint64 `json:"end_time,omitempty"` + TimestampMS uint64 `json:"timestamp,omitempty"` + Type string `json:"type"` + Aliases []string `json:"aliases,omitempty"` + } var in requestQuery after := in.After out := in out.After = after - client.Call(context.Background(),"/list-unspent-outputs",&[]requestQuery{in,},nil) + client.Call(context.Background(), "/list-unspent-outputs", &[]requestQuery{in}, nil) +} + +func createAccessToken(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:createAccessToken not use args") + } + type Token struct { + ID string `json:"id"` + Token string `json:"token,omitempty"` + Type string `json:"type,omitempty"` // deprecated in 1.2 + Created time.Time `json:"created_at"` + sortID string + } + var token Token + token.ID = "Alice" + token.Token = "token" + + client.Call(context.Background(), "/create-access-token", &[]Token{token}, nil) +} + +func listAccessTokens(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:listAccessTokens not use args") + } + type Token struct { + ID string `json:"id"` + Token string `json:"token,omitempty"` + Type string `json:"type,omitempty"` // deprecated in 1.2 + Created time.Time `json:"created_at"` + sortID string + } + var token Token + token.ID = "Alice" + token.Token = "token" + + client.Call(context.Background(), "/list-access-token", &[]Token{token}, nil) +} +func deleteAccessToken(client *rpc.Client, args []string) { + if len(args) != 0 { + fatalln("error:deleteAccessToken not use args") + } + type Token struct { + ID string `json:"id"` + Token string `json:"token,omitempty"` + Type string `json:"type,omitempty"` // deprecated in 1.2 + Created time.Time `json:"created_at"` + sortID string + } + var token Token + token.ID = "Alice" + token.Token = "token" + + client.Call(context.Background(), "/delete-access-token", &[]Token{token}, nil) }