Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to create the original Dashboard

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "how to create the original Dashboard". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn how to create the original Dashboard.

How do we enable the Dashboard function in Bihara?

When we use bytomd node to start the original node, it will automatically enable the Dashboard function without any configuration, and it will open the page in the browser, which is very convenient.

If this is the first time to run an account and has not yet created an account, it will prompt us to create an account and the associated private key:

We can create it by filling in the account alias, key alias and corresponding password, or click "Restore wallet" below to restore the previous account (if it was previously backed up):

After clicking "Register", it will be created successfully and go to the management page:

Note that its address is: http://127.0.0.1:9888/dashboard

If we look at the configuration file config.toml, we can see it in it:

Fast_sync = truedb_backend = "leveldb" api_addr = "0.0.0.0 api_addr 9888" chain_id = "solonet" [P2P] laddr = "tcp://0.0.0.0:46658" seeds = ""

Notice that the api_addr is the address of dashboard and web-api. After Bihara starts, its BaseConfig.ApiAddress fetches the corresponding value from the configuration file:

Config/config.go#L41-L85

Type BaseConfig struct {/ /... ApiAddress string `mapstructure: "api_addr" `/ /...}

Then on startup, the original web api and dashboard will use this address and open dashboard in the browser.

A strange problem here, however, is that no matter what the value here, the browser always opens the http://localhost:9888 address. Why? Because it died in the code.

In the code, http://localhost:9888 appears in three places. One is used to represent the access address of dashboard, which is located in node/node.go:

Node/node.go#L33-L37

Const (webAddress = "http://127.0.0.1:9888" expireReservationsPeriod = time.Second maxNewBlockChSize = 1024)

The webAddress here is used only when you open a browser to display dashboard from the code:

Node/node.go#L153-L159

Func lanchWebBroser () {log.Info ("Launching System Browser with:", webAddress) if err: = browser.Open (webAddress); err! = nil {log.Error (err.Error ()) return}}

Through the original "github.com/toqueteos/webbrowser" this third-party library, you can call the default browser of the system when the node starts, and open the specified URL, which is convenient for users. (note that there are many typos in this code, such as lanch and broser, which have been fixed in subsequent versions.)

Another place is for the command-line tool bytomcli, which is strangely placed under util/util.go:

Util/util.go#L26-L28

Var (coreURL = env.String ("BYTOM_URL", "http://localhost:9888"))")

Why does it belong to bytomcli? Because this coreURL is finally used in a ClientCall (...) under the util package. Function to send a request from the code to the specified web api and use its reply message. But this method is used in the package where bytomcli is located. If so, coreURL and related functions should be moved to the bytomcli package.

The third place, very similar to the second, but in tools/sendbulktx/core/util.go, is for another command-line tool, sendbulktx:

Tools/sendbulktx/core/util.go#L26-L28

Var (coreURL = env.String ("BYTOM_URL", "http://localhost:9888"))")

It's exactly the same, right. In fact, not only here, there are a number of related methods and functions, but also exactly the same, at a glance is copied from the second place.

With regard to the question here, I have two issue:

The addresses of dashboard and web api are written in the configuration file config.toml, but they are written in the code at the same time: it is indeed difficult to implement here, because in the configuration file, it is written as 0.0.0.0config.toml 9998, but when accessing from the browser or command line tool, you need to use a specific ip (not 0.0.0.0), otherwise some functions will not work properly. In addition, the code analysis office will see that in addition to this address in the configuration file, it will take precedence over the original to obtain the address web api of the address corresponding to LISTEN from the environment variable. So more research is needed here to fix it correctly.

There is a lot of repetition in the code associated with reading webapi: the official explanation is that the sendbulktx tool will be independent from the bytom project in the future, so the code is duplicated, if so, it is acceptable.

What information and functions are available in Dashboard?

Let's take a quick look at what information and functions are provided by the original Dashboard. Since in this article, we do not focus on these specific functions, we will not take a closer look. In addition, a lot of data is not available in the account I just created. In order to show it easily, I made some data in advance.

The first is the key:

This shows how many keys currently exist, what their aliases are, and show the primary public key. We can click the "New" button in the upper right corner to create multiple keys, but it is no longer shown here.

Account:

Assets:

Only BTM is defined by default, and multiple assets can be added through the New button.

Balance:

It looks like I still have a lot of money (unfortunately I can't use it).

Deal:

Shows a number of deals, which were actually dug up in the local mine. Since the mined BTM is transferred directly to our account by the system, it can also be regarded as a transaction.

Create a deal:

We can also create our own transactions like this and transfer some of our holdings (such as BTM) to another address.

Unspent output:

The simple understanding is that every transaction related to me is recorded, with input and output, and the output may be the input of another transaction. What is shown here is the output that has not yet been spent (you can use it to calculate how much balance I have left).

View the core status:

Define access control:

Backup and restore operations:

In addition, under the left column of each page, there is also about the type of chain connected (in this case, solonet), as well as synchronization and the number of other nodes connected to the current node.

The information and functions shown here do not need to be studied in detail, but the nouns that appear here should be paid attention to because they are the core concepts of the original. When we study the core functions of the original internal block chain in the future, we actually revolve around them. Each concept here may need to be discussed in one or more articles.

What we are focusing on today is the technical implementation level, and now we are going to get into code time.

How did Bihara implement the http server?

First of all, let's start from the original node and find the place to start the http service:

Cmd/bytomd/main.go#L54-L57

Func main () {cmd: = cli.PrepareBaseCmd (commands.RootCmd, "TM", os.ExpandEnv (config.DefaultDataDir ()) cmd.Execute ()}

Cmd/bytomd/commands/run_node.go#L41-L54

Func runNode (cmd * cobra.Command, args [] string) error {/ / Create & start node n: = node.NewNode (config) if _, err: = n.Start (); err! = nil {/ /..}

Node/node.go#L169-L180

Func (n * Node) OnStart () error {/ /... N.initAndstartApiServer () / /.}

I found it soon, initAndstartApiServer:

Node/node.go#L161-L167

Func (n * Node) initAndstartApiServer () {/ / 1. N.api = api.NewAPI (n.syncManager, n.wallet, n.txfeed, n.cpuMiner, n.miningPool, n.chain, n.config, n.accessTokens) / / 2. ListenAddr: = env.String ("LISTEN", n.config.ApiAddress) env.Parse () / 3. N.api.StartServer (* listenAddr)}

As you can see, the method is divided into three parts:

An API object is constructed by passing in a large number of parameters. When you go in, you will see a large number of url-related configurations.

First get the corresponding value of LISTEN from the environment, and if not, use the api_ addr value specified in config.toml as the entry address of the api service

Really start the service

Since 2 is relatively simple, we will analyze 1 and 3 in detail below.

First find the api.NewAPI method corresponding to 1:

Api/api.go#L143-L157

Func NewAPI (sync * netsync.SyncManager, wallet * wallet.Wallet, txfeeds * txfeed.Tracker, cpuMiner * cpuminer.CPUMiner, miningPool * miningpool.MiningPool, chain * protocol.Chain, config * cfg.Config, token * accesstoken.CredentialStore) * API {api: = & API {sync: sync, wallet: wallet, chain: chain, accessTokens: token, txFeedTracker: txfeeds, cpuMiner: cpuMiner MiningPool: miningPool,} api.buildHandler () api.initServer (config) return api}

It is mainly to hold the parameters passed in for later use. Then there is api.buildHandler to configure the paths and handlers of each function point, and to initialize the service with api.initServer.

Enter api.buildHandler (). This method is a bit long. Divide it into several parts to explain:

Api/api.go#L164-L244

Func (a * API) buildHandler () {walletEnable: = false m: = http.NewServeMux ()

It seems that the http service uses the http package that comes with Go.

Downwards, when the user's wallet feature is not disabled, various function points related to the wallet (such as account number, transaction, key, etc.) will be configured:

If a.wallet! = nil {walletEnable = true m.Handle ("/ create-account", jsonHandler (a.createAccount)) m.Handle ("/ list-accounts", jsonHandler (a.listAccounts)) m.Handle ("/ delete-account", jsonHandler (a.deleteAccount)) m.Handle ("/ create-account-receiver", jsonHandler (a.createAccountReceiver)) m.Handle ("/ list-addresses") JsonHandler (a.listAddresses)) m.Handle ("/ validate-address", jsonHandler (a.validateAddress)) m.Handle ("/ create-asset", jsonHandler (a.createAsset)) m.Handle ("/ update-asset-alias", jsonHandler (a.updateAssetAlias)) m.Handle ("/ get-asset", jsonHandler (a.getAsset)) m.Handle ("/ list-assets") JsonHandler (a.listAssets)) m.Handle ("/ create-key", jsonHandler (a.pseudohsmCreateKey)) m.Handle ("/ list-keys", jsonHandler (a.pseudohsmListKeys)) m.Handle ("/ delete-key", jsonHandler (a.pseudohsmDeleteKey)) m.Handle ("/ reset-key-password", jsonHandler (a.pseudohsmResetPassword)) m.Handle ("/ build-transaction") JsonHandler (a.build)) m.Handle ("/ sign-transaction", jsonHandler (a.pseudohsmSignTemplates)) m.Handle ("/ submit-transaction", jsonHandler (a.submit)) m.Handle ("/ estimate-transaction-gas", jsonHandler (a.estimateTxGas)) m.Handle ("/ get-transaction", jsonHandler (a.getTransaction)) m.Handle ("/ list-transactions") JsonHandler (a.listTransactions)) m.Handle ("/ list-balances", jsonHandler (a.listBalances)) m.Handle ("/ list-unspent-outputs", jsonHandler (a.listUnspentOutputs)) m.Handle ("/ backup-wallet", jsonHandler (a.backupWalletImage)) m.Handle ("/ restore-wallet", jsonHandler (a.restoreWalletImage))} else {log.Warn ("Please enable wallet")}

The wallet feature is enabled by default. How can users disable it? This is done by adding this section of code to the configuration file config.toml:

[wallet] disable = true

In the previous code, when configuring the function point, you used a lot of code like m.Handle ("/ create-account", jsonHandler (a.createAccount)). What does it mean?

/ create-account: the path to this feature, for example, the user needs to use the address http://localhost:9888/create-account in the browser or command line to access it.

A.createAccount: used to handle user access, such as getting the data provided by the user, and then returning some data to the user after processing, which will be explained in detail below

JsonHandler: is an intermediate layer that converts the JSON data sent by the user into the Go type parameters required by step 2 handler, or converts the Go data returned by 2 into JSON to the user

M.Handle (path, handler): used to correspond the function point path to the corresponding processing function

Let's take a look at the jsonHandler code in step 3:

Api/api.go#L259-L265

Func jsonHandler (f interface {}) http.Handler {h, err: = httpjson.Handler (f, errorFormatter.Write) if err! = nil {panic (err)} return h}

It uses httpjson, which is more than a package provided in the original code, located in net/http/httpjson. Its function is mainly to add a layer of conversion between http access and Go functions. Usually, when users interact with api through http, they send and receive JSON data, but what we define in step 2 of handler is the Go function. Through httpjson, we can automatically convert between the two, so that we do not need to consider the problems related to JSON and http protocol when writing Go code. Accordingly, in order to work with jsonhttp, there will be some format requirements for handler in step 2, as detailed in the detailed note here: net/http/httpjson/doc.go#L3-L40. As there is still a lot of code involved in httpjson, I will not elaborate on it here. I will have the opportunity to write a special article in the future.

Then let's look at the a.createAccount code in step 2:

Api/accounts.go#L16-L30

Func (a * API) createAccount (ctx context.Context, ins struct {RootXPubs [] chainkd.XPub `json: "root_xpubs" `Quorum int `json: "quorum" `Alias string `json: "alias" `}) Response {acc, err: = a.wallet.AccountMgr.Create (ctx, ins.RootXPubs, ins.Quorum) Ins.Alias) if err! = nil {return NewErrorResponse (err)} annotatedAccount: = account.Annotated (acc) log.WithField ("account ID", annotatedAccount.ID) .Info ("Created account") return NewSuccessResponse (annotatedAccount)}

We won't delve into the content of this function here, but what we need to pay attention to is its format, because as mentioned earlier, it needs to be used with jsonHandler. The format probably requires that the first parameter is Context, the second parameter is a parameter that can be converted from JSON data, and the return values are a Response and an Error, but all four are optional.

Let's go back to api.buildHandler () and move on:

M.Handle ("/", alwaysError (errors.New ("not Found")) m.Handle ("/ error", jsonHandler (a.walletError)) m.Handle ("/ create-access-token", jsonHandler (a.createAccessToken)) m.Handle ("/ list-access-tokens", jsonHandler (a.listAccessTokens)) m.Handle ("/ delete-access-token", jsonHandler (a.deleteAccessToken)) m.Handle ("/ check-access-token") JsonHandler (a.checkAccessToken)) m.Handle ("/ create-transaction-feed", jsonHandler (a.createTxFeed)) m.Handle ("/ get-transaction-feed", jsonHandler (a.getTxFeed)) m.Handle ("/ update-transaction-feed", jsonHandler (a.updateTxFeed)) m.Handle ("/ delete-transaction-feed", jsonHandler (a.deleteTxFeed)) m.Handle ("/ list-transaction-feeds", jsonHandler (a.listTxFeeds)) m.Handle ("/ get-unconfirmed-transaction") JsonHandler (a.getUnconfirmedTx)) m.Handle ("/ list-unconfirmed-transactions", jsonHandler (a.listUnconfirmedTxs)) m.Handle ("/ get-block-hash", jsonHandler (a.getBestBlockHash)) m.Handle ("/ get-block-header", jsonHandler (a.getBlockHeader)) m.Handle ("/ get-block", jsonHandler (a.getBlock)) m.Handle ("/ get-block-count", jsonHandler (a.getBlockCount)) m.Handle ("/ get-difficulty") JsonHandler (a.getDifficulty)) m.Handle ("/ get-hash-rate", jsonHandler (a.getHashRate)) m.Handle ("/ is-mining", jsonHandler (a.isMining)) m.Handle ("/ set-mining", jsonHandler (a.setMining)) m.Handle ("/ get-work", jsonHandler (a.getWork)) m.Handle ("/ submit-work", jsonHandler (a.submitWork)) m.Handle ("/ gas-rate") JsonHandler (a.gasRate)) m.Handle ("/ net-info", jsonHandler (a.getNetInfo))

It can be seen that the definition of various functions, mainly related to block data, mining, access control and other functions, will not be detailed here.

Then go on:

Handler: = latencyHandler (m, walletEnable) handler = maxBytesHandler (handler) handler = webAssetsHandler (handler) handler = gzip.Handler {Handler: handler} a.handler = handler}

Here, the previously defined function point configuration is packaged into a handler, and then layer after layer is wrapped around it, adding more functions:

LatencyHandler: I can't say exactly what it does at the moment. I'll add it later.

MaxBytesHandler: prevents the data submitted by users from being too large. The current value is about 10MB. Valid for url other than signer/sign-block

WebAssetsHandler: provide users with dashboard-related front-end page resources (such as web pages, images, etc.). Perhaps for the sake of performance and convenience, the front-end files are confused and embedded in dashboard/dashboard.go as strings, and the real code is https://github.com/Bytom/dashboard in another project, which we'll take a look at later.

Gzip.Handler: detects whether the http client supports gzip and, if so, uses gzip compression when transferring data

Then let's go back to the main line and take a look at the last called api.initServer (config) in the previous NewAPI:

Api/api.go#L89-L122

Func (a * API) initServer (config * cfg.Config) {/ / The waitHandler accepts incoming requests, but blocks until its underlying / / handler is set, when the second phase is complete. Var coreHandler waitHandler var handler http.Handler coreHandler.wg.Add (1) mux: = http.NewServeMux () mux.Handle ("/", & coreHandler) handler = mux if config.Auth.Disable = false {handler = AuthHandler (handler, a.accessTokens)} handler = RedirectHandler (handler) secureheader.DefaultConfig.PermitClearLoopback = true secureheader.DefaultConfig.HTTPSRedirect = false secureheader.DefaultConfig.Next = handler a.server = & http.Server {/ / Note: we should not set TLSConfig here / / we took care of TLS with the listener in maybeUseTLS. Handler: secureheader.DefaultConfig, ReadTimeout: httpReadTimeout, WriteTimeout: httpWriteTimeout, / / Disable HTTP/2 for now until the Go implementation is more stable. / / https://github.com/golang/go/issues/16450 / / https://github.com/golang/go/issues/17071 TLSNextProto: map [string] func (* http.Server, * tls.Conn, http.Handler) {},} coreHandler.Set (a)

This method is not suitable for details in this article, because it is more related to something at the http level and is not the focus of this article. What's worth noting is that the method creates a http.Server provided by Go, stuffing in the handler that we painstakingly configured earlier, and everything is ready, just for startup.

Here is the start. We can finally go back to the latest initAndstartApiServer method, remember its third piece of content? It mainly calls n.api.StartServer (* listenAddr):

Api/api.go#L125-L140

Func (a * API) StartServer (address string) {/ /... Listener, err: = net.Listen ("tcp", address) / /. Go func () {if err: = a.server.Serve (listener); err! = nil {log.WithField ("error", errors.Wrap (err, "Serve"). Error ("Rpc server")}} ()} ()

This piece is relatively simple, that is, use the net.Listen of Go to listen for the incoming web api address, get the corresponding listener, pass it to the Serve method of the http.Server we created earlier, and you are done.

This piece of code analysis is very painful to write, mainly because its web api here involves almost all the functions provided by the original, very complex. There are also a lot of things related to the http agreement. At the same time, because the interface is exposed, it is prone to security risks, so there are a lot of user input, security checks and so on in the code. Of course, these things are very important, but from a code reading point of view, it is inevitably boring, unless we are looking at security.

The main task of this paper is to study how Biyuan provides http services, and there will be a special analysis on what has been done in security.

What front-end framework does Dashboard use?

Beehara's front-end code is in another separate project: https://github.com/Bytom/dashboard

In this article, we won't go into the details of the code, but just take a look at which front-end frameworks it uses and have a general impression.

Through https://github.com/Bytom/dashboard/blob/master/package.json, we can get a general idea that compared to the original front end, we can use:

Build tools: directly leverage npm's Scripts

Front-end framework: React + Redux

CSS: bootstrap

JavaScript:ES6

Http request: fetch-ponyfill

Resource packaging: webpack

Test: mocha

In what way did you get the data on Dashboard from the background?

Take the Account-related code as an example:

Src/sdk/api/accounts.js#L16

Const accountsAPI = (client) = > {return {create: (params, cb) = > shared.create (client,'/ create-account', params, {cb, skipArray: true}), createBatch: (params, cb) = > shared.createBatch (client,'/ create-account', params, {cb}), / /. ListAddresses: (accountId) = > shared.query (client, 'accounts',' / list-addresses', {account_id: accountId}),}}

These functions mainly send http requests to the web api interface created using go and get the corresponding reply data through the methods provided in the fetch-ponyfill library. They will be called in the React component, and the returned data will be used to populate the page.

Thank you for your reading, the above is the content of "how to create the original Dashboard". After the study of this article, I believe you have a deeper understanding of how to create the original Dashboard, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

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.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report