In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the relevant knowledge of "how to create an address through create-account-receiver". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
How does the front end send requests to the background interface?
The first is the React component corresponding to "Create Address" in the page.
Class AccountShow extends BaseShow {/ /... / 2. CreateAddress () {/ /... / / 3. This.props.createAddress ({account_alias: this.props.item.alias}) .then (({data}) = > {this.listAddress () this.props.showModal (
{lang = = 'zh'? 'copy this address for use in the transaction:': 'Copy this address to use in a transaction:'}
)} render () {/ /... View = / /...} / /.}}
The first place above is the code corresponding to the "Create Address" link, which is actually a Button, and when clicked, the createAddress method is called. And the second place is the createAddress method, and in the third place in it, you will call this.props.createAddress, the createAddress function passed in from the outside. At the same time, it also sends a parameter account_alias that corresponds to the alias of the current account.
Continue to find the definition of createAddress
Const accountsAPI = (client) = > {return {/ /... CreateAddress: (params, cb) = > shared.create (client,'/ create-account-receiver', params, {cb, skipArray: true}), / /...}}
As you can see, it calls / create-account-receiver than the original interface.
Then we will enter the original backstage.
How does the original backend create an address?
In the original code, we can find the handler corresponding to interface / create-account-receiver:
Api/api.go#L164-L174
Func (a * API) buildHandler () {/ /... If a.wallet! = nil {/ /... M.Handle ("/ create-account-receiver", jsonHandler (a.createAccountReceiver))
It turned out to be a.createAccountReceiver. Let's keep going in:
Api/receivers.go#L9-L32
/ / 1.func (a * API) createAccountReceiver (ctx context.Context, ins struct {AccountID string `json: "account_id" `AccountAlias string `json: "account_alias" `}) Response {/ / 2. AccountID: = ins.AccountID if ins.AccountAlias! = "{account, err: = a.wallet.AccountMgr.FindByAlias (ctx) Ins.AccountAlias) if err! = nil {return NewErrorResponse (err)} accountID = account.ID} / / 3. Program, err: = a.wallet.AccountMgr.CreateAddress (ctx, accountID, false) if err! = nil {return NewErrorResponse (err)} / / 4. Return NewSuccessResponse (& txbuilder.Receiver {ControlProgram: program.ControlProgram, Address: program.Address })}
The code in the method can be divided into four pieces, which still looks clear:
The focus of block 1 is mainly on the parameters. As you can see, this interface can receive two parameters account_id and account_alias, but just now the front-end code passed account_alias this one, what's going on?
As you can see from block 2, if the parameter account_alias is passed, it will prevail, use it to find the corresponding account, and then get the corresponding id. Otherwise, use account_id as the id of account
The third block is to create an address for the corresponding account of accountID
The fourth block returns the success information, which is converted to a JSON object through the external jsonHandler and sent to the front end.
Here, we need to focus on only two methods, namely, a.wallet.AccountMgr.FindByAlias in block 2 and a.wallet.AccountMgr.CreateAddress in block 3, which we study in turn.
A.wallet.AccountMgr.FindByAlias
Go directly to the code:
Account/accounts.go#L176-L195
/ FindByAlias retrieves an account's Signer record by its aliasfunc (m * Manager) FindByAlias (ctx context.Context, alias string) (* Account, error) {/ / 1. M.cacheMu.Lock () cachedID, ok: = m.aliasCache.Get (alias) m.cacheMu.Unlock () if ok {return m.FindByID (ctx) CachedID. (string))} / / 2. RawID: = m.db.Get (aliasKey (alias)) if rawID = = nil {return nil, ErrFindAccount} / 3. AccountID: = string (rawID) m.cacheMu.Lock () m.aliasCache.Add (alias, accountID) m.cacheMu.Unlock () return m.FindByID (ctx, accountID)}
The structure of this method is also relatively simple, which is divided into three parts:
Directly use alias to find the corresponding id in the memory cache aliasCache, and then call FindByID to find the complete account data.
If it is not found in the cache, change the alias into the form required by the database and look for id in the database. If you can't find it, report an error.
If you find it, put alias and id in memory cache for later use, and call FindByID to find the complete account data.
The aliasCache mentioned above is a field defined in the Manager type:
Account/accounts.go#L78-L85
Type Manager struct {/ /... AliasCache * lru.Cache
Lru.Cache is provided by the Go language, so let's not delve into it.
Then there is the FindByID used many times:
Account/accounts.go#L197-L220
/ FindByID returns an account's Signer record by its ID.func (m * Manager) FindByID (ctx context.Context, id string) (* Account, error) {/ / 1. M.cacheMu.Lock () cachedAccount, ok: = m.cache.Get (id) m.cacheMu.Unlock () if ok {return cachedAccount. (* Account) Nil} / / 2.rawAccount: = m.db.Get (Key (id)) if rawAccount = = nil {return nil, ErrFindAccount} / / 3. Account: = & Account {} if err: = json.Unmarshal (rawAccount, account) Err! = nil {return nil, err} / / 4. M.cacheMu.Lock () m.cache.Add (id, account) m.cacheMu.Unlock () return account, nil}
This method is the same as the previous routine, but also relatively clear:
Look for it in the memory cache cache first, and return it directly when you find it. M.cache is also a lru.Cache object defined in Manager
If it is not in the memory cache, look for it in the database and find the corresponding account object data in JSON format according to id.
Change the data in JSON format into data of type Account, which is what you need before.
Put it in the memory cache cache, using id as the key
There is nothing to say here, because it is basically covered in the previous article.
A.wallet.AccountMgr.CreateAddress
Continue to look at the method of generating addresses:
Account/accounts.go#L239-L246
/ CreateAddress generate an address for the select accountfunc (m * Manager) CreateAddress (ctx context.Context, accountID string, change bool) (cp * CtrlProgram, err error) {account, err: = m.FindByID (ctx, accountID) if err! = nil {return nil, err} return m.createAddress (ctx, account, change)}
Since the accountID rather than the account object is passed in this method, you need to check it again with FindByID, and then call the private method createAddress to create the address:
Account/accounts.go#L248-L263
/ 1.func (m * Manager) createAddress (ctx context.Context, account * Account, change bool) (cp * CtrlProgram, err error) {/ / 2. If len (account.XPubs) = = 1 {cp, err = m.createP2PKH (ctx, account, change)} else {cp, err = m.createP2SH (ctx, account, change)} if err! = nil {return nil Err} / / 3. If err = m.insertAccountControlProgram (ctx, cp) Err! = nil {return nil, err} return cp, nil}
The method can be divided into three parts:
The main concern in block 1 is the return value. The method is named CreateAddress, but returns a value or CtrlProgram, so where is the Address? Address is actually a field in CtrlProgram, so the caller can get the Address
There is a new discovery here in the second block of code that an account can have multiple key pairs (reminder: in elliptical algorithms, a private key can only have one public key). Because different methods will be called here depending on the number of public keys owned by the account. If the number of public keys is 1, the account is an exclusive account (managed by a key) and m.createP2PKH will be called; otherwise, the account is managed by multiple public keys (possibly a federated account) and m.createP2SH needs to be called. These two methods, the returned object cp, refers to ControlProgram, emphasizing that it is a control program, not an address, and the address Address is just a field of it.
Once created, insert the control program into the account
Let's first look at the case where the account in block 2 has only one key, and the method called is createP2PKH:
Account/accounts.go#L265-L290
Func (m * Manager) createP2PKH (ctx context.Context, account * Account, change bool) (* CtrlProgram, error) {idx: = m.getNextContractIndex (account.ID) path: = signers.Path (account.Signer, signers.AccountKeySpace, idx) derivedXPubs: = chainkd.DeriveXPubs (account.XPubs, path) derivedPK: = derivedXPubs [0] .PublicKey () pubHash: = crypto.Ripemd160 (derivedPK) / / TODO: pass different params due to config address, err: = common.NewAddressWitnessPubKeyHash (pubHash) & consensus.ActiveNetParams) if err! = nil {return nil, err} control, err: = vmutil.P2WPKHProgram ([] byte (pubHash)) if err! = nil {return nil, err} return & CtrlProgram {AccountID: account.ID, Address: address.EncodeAddress (), KeyIndex: idx, ControlProgram: control, Change: change,} Nil}
I'm sorry, I can't handle the code of this method as soon as I see it, and it seems to have touched the core of the original chain. It is difficult for us to explain it reasonably through these lines of code and quick reference, so we can only skip it in this article and study it later. Similarly, m.createP2SH is the same, let's skip it first. We'll settle this piece sooner or later. Please wait.
Let's move on to the m.insertAccountControlProgram method in block 3:
Account/accounts.go#L332-L344
Func (m * Manager) insertAccountControlProgram (ctx context.Context, progs... * CtrlProgram) error {var hash common.Hash for _, prog: = range progs {accountCP, err: = json.Marshal (prog) if err! = nil {return err} sha3pool.Sum256 (hash [:], prog.ControlProgram) m.db.Set (ContractKey (hash), accountCP)} return nil}
This method looks much easier, mainly by passing the previously created CtrlProgram and saving the database to it. Note that the second argument to this method is... * CtrlProgram, which is a mutable parameter, but when used in this article, only one value is passed (multiple values are passed in in other uses).
In the method, variables are made to progs, and for each of them, it is first converted to JSON format, then it is summarized, and finally the summary is prefixed with a Contract: through the ContractKey function and placed in the database. The m.db here is analyzed in the previous article, and it is the leveldb database called wallet. The Key of this database is very complex, saving various types of data, prefix distinction.
Let's take a look at the ContractKey function, which is simple:
Account/accounts.go#L57-L59
Func ContractKey (hash common.Hash) [] byte {return append (contractPrefix, hash [:]...)}
Where contractPrefix is the constant [] byte ("Contract:"). From this name, we can come into contact with a new concept: Contract. It seems that the previous CtrlProgram is a contract, and the account is only part of the contract (whether this is the case, leave it for us to verify later).
That's all for the content of "how to create an address through create-account-receiver". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.