diff --git a/assets/clef_qubes_http.png b/assets/clef_qubes_http.png deleted file mode 100644 index e95ad8da4a..0000000000 Binary files a/assets/clef_qubes_http.png and /dev/null differ diff --git a/assets/clef_qubes_qrexec.png b/assets/clef_qubes_qrexec.png deleted file mode 100644 index b1814e7c36..0000000000 Binary files a/assets/clef_qubes_qrexec.png and /dev/null differ diff --git a/assets/clef_sign_flow.png b/assets/clef_sign_flow.png deleted file mode 100644 index 906384cf22..0000000000 Binary files a/assets/clef_sign_flow.png and /dev/null differ diff --git a/assets/devcon2_labelled.webp b/assets/devcon2_labelled.webp deleted file mode 100644 index 321326e64a..0000000000 Binary files a/assets/devcon2_labelled.webp and /dev/null differ diff --git a/assets/ethstats-mainnet.png b/assets/ethstats-mainnet.png deleted file mode 100644 index 080dd335fc..0000000000 Binary files a/assets/ethstats-mainnet.png and /dev/null differ diff --git a/assets/grafana1.png b/assets/grafana1.png deleted file mode 100644 index 24afabebdd..0000000000 Binary files a/assets/grafana1.png and /dev/null differ diff --git a/assets/grafana2.png b/assets/grafana2.png deleted file mode 100644 index ca01d2ad4a..0000000000 Binary files a/assets/grafana2.png and /dev/null differ diff --git a/assets/grafana3.png b/assets/grafana3.png deleted file mode 100644 index e66c61b2cb..0000000000 Binary files a/assets/grafana3.png and /dev/null differ diff --git a/assets/grafana4.png b/assets/grafana4.png deleted file mode 100644 index 9136e0e428..0000000000 Binary files a/assets/grafana4.png and /dev/null differ diff --git a/assets/grafana5.png b/assets/grafana5.png deleted file mode 100644 index ff385fedcd..0000000000 Binary files a/assets/grafana5.png and /dev/null differ diff --git a/assets/grafana6.png b/assets/grafana6.png deleted file mode 100644 index 39950e5497..0000000000 Binary files a/assets/grafana6.png and /dev/null differ diff --git a/assets/grafana7.png b/assets/grafana7.png deleted file mode 100644 index ff15dba872..0000000000 Binary files a/assets/grafana7.png and /dev/null differ diff --git a/assets/grafana8.png b/assets/grafana8.png deleted file mode 100644 index f4ede6a965..0000000000 Binary files a/assets/grafana8.png and /dev/null differ diff --git a/assets/node_architecture.png b/assets/node_architecture.png deleted file mode 100644 index 5b0bd1baad..0000000000 Binary files a/assets/node_architecture.png and /dev/null differ diff --git a/assets/node_basic.png b/assets/node_basic.png deleted file mode 100644 index 2add22296c..0000000000 Binary files a/assets/node_basic.png and /dev/null differ diff --git a/assets/qrexec-example.png b/assets/qrexec-example.png deleted file mode 100644 index fc5d57725d..0000000000 Binary files a/assets/qrexec-example.png and /dev/null differ diff --git a/assets/qubes-client.py b/assets/qubes-client.py deleted file mode 100644 index 93a74b899b..0000000000 --- a/assets/qubes-client.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This implements a dispatcher which listens to localhost:8550, and proxies -requests via qrexec to the service qubes.EthSign on a target domain -""" - -import http.server -import socketserver,subprocess - -PORT=8550 -TARGET_DOMAIN= 'debian-work' - -class Dispatcher(http.server.BaseHTTPRequestHandler): - def do_POST(self): - post_data = self.rfile.read(int(self.headers['Content-Length'])) - p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) - output = p.communicate(post_data)[0] - self.wfile.write(output) - - -with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: - print("Serving at port", PORT) - httpd.serve_forever() - diff --git a/assets/qubes.Clefsign b/assets/qubes.Clefsign deleted file mode 100644 index 9b5af7b4fe..0000000000 --- a/assets/qubes.Clefsign +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -SIGNER_BIN="/home/user/tools/clef/clef" -SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" - -# Start clef if not already started -if [ ! -S /home/user/.clef/clef.ipc ]; then - $SIGNER_CMD & - sleep 1 -fi - -# Should be started by now -if [ -S /home/user/.clef/clef.ipc ]; then - # Post incoming request to HTTP channel - curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null -fi diff --git a/assets/qubes_newaccount-1.png b/assets/qubes_newaccount-1.png deleted file mode 100644 index 3bfc8b5b7e..0000000000 Binary files a/assets/qubes_newaccount-1.png and /dev/null differ diff --git a/assets/qubes_newaccount-2.png b/assets/qubes_newaccount-2.png deleted file mode 100644 index c6dbd535dd..0000000000 Binary files a/assets/qubes_newaccount-2.png and /dev/null differ diff --git a/assets/remix-compiler.png b/assets/remix-compiler.png deleted file mode 100644 index 8c9255711b..0000000000 Binary files a/assets/remix-compiler.png and /dev/null differ diff --git a/assets/remix-deploy.png b/assets/remix-deploy.png deleted file mode 100644 index cea10898bf..0000000000 Binary files a/assets/remix-deploy.png and /dev/null differ diff --git a/assets/remix-func.png b/assets/remix-func.png deleted file mode 100644 index 797e665177..0000000000 Binary files a/assets/remix-func.png and /dev/null differ diff --git a/assets/remix.png b/assets/remix.png deleted file mode 100644 index bff8c709de..0000000000 Binary files a/assets/remix.png and /dev/null differ diff --git a/assets/wireframe1.png b/assets/wireframe1.png deleted file mode 100644 index 036339b0ee..0000000000 Binary files a/assets/wireframe1.png and /dev/null differ diff --git a/assets/wireframe2.png b/assets/wireframe2.png deleted file mode 100644 index 435f8f7f1f..0000000000 Binary files a/assets/wireframe2.png and /dev/null differ diff --git a/assets/wireframe3.png b/assets/wireframe3.png deleted file mode 100644 index 1f2de2f031..0000000000 Binary files a/assets/wireframe3.png and /dev/null differ diff --git a/assets/wireframe4.png b/assets/wireframe4.png deleted file mode 100644 index 26be100b88..0000000000 Binary files a/assets/wireframe4.png and /dev/null differ diff --git a/assets/wireframe5.png b/assets/wireframe5.png deleted file mode 100644 index 202f0b8d32..0000000000 Binary files a/assets/wireframe5.png and /dev/null differ diff --git a/content/docs/developers/contributing.md b/content/docs/developers/contributing.md deleted file mode 100644 index 522ecf8845..0000000000 --- a/content/docs/developers/contributing.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Contributing -description: Guidlines for contributing to Geth ---- - -We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes! - -## Contributing to the Geth source code - -If you'd like to contribute to the Geth source code, please fork the [Github repository](https://github.com/ethereum/go-ethereum), fix, commit and send a pull request for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check up with the core devs first on our Discord Server to ensure those changes are in line with the general philosophy of the project and/or get some early feedback which can make both your efforts much lighter as well as our review and merge procedures quick and simple. - -Please make sure your contributions adhere to our coding guidelines: - -- Code must adhere to the official Go formatting guidelines (i.e. uses gofmt). -- Code must be documented adhering to the official Go commentary guidelines. -- Pull requests need to be based on and opened against the master branch. -- Commit messages should be prefixed with the package(s) they modify. - E.g. "eth, rpc: make trace configs optional" - -Pull requests generally need to be based on and opened against the `master` branch, unless by explicit agreement because the work is contributing to some more complex feature branch. - -All pull requests will be reviewed according to the [Code Review guidelines](/content/docs/developers/geth-developer/code-review-guidelines.md). - -We encourage an early pull request approach, meaning pull requests are created as early as possible even without the completed fix/feature. This will let core devs and other volunteers know you picked up an issue. These early PRs should indicate 'in progress' status. - -## Contributing to the Geth website - -The Geth website is hosted separately from Geth itself. The contribution guidelines are the same. Please for the Geth website Github repository and raise pull requests for the maintainers to review and merge. - -## License - -The go-ethereum library (i.e. all code outside of the cmd directory) is licensed under the GNU Lesser General Public License v3.0, also included in our repository in the COPYING.LESSER file. - -The go-ethereum binaries (i.e. all code inside of the cmd directory) is licensed under the GNU General Public License v3.0, also included in our repository in the COPYING file. diff --git a/content/docs/developers/dapp-developer/built-in-tracers.md b/content/docs/developers/dapp-developer/built-in-tracers.md deleted file mode 100644 index 2c93414daf..0000000000 --- a/content/docs/developers/dapp-developer/built-in-tracers.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Built-in tracers -description: Explanation of the tracers that come bundled in Geth as part of the tracing API. ---- - -Geth comes bundled with a choice of tracers ready for usage through the [tracing API](/docs/rpc/ns-debug). Some of them are implemented natively in Go, and others in JS. In this page a summary of each of these will be outlined. They have to be specified by name when sending a request. The only exception is the opcode logger (otherwise known as struct logger) which is the default tracer for all the methods and cannot be specified by name. - -## Struct logger - -Struct logger or opcode logger is a native Go tracer which executes a transaction and emits the opcode and execution context at every step. This is the tracer that will be used when no name is passed to the API, e.g. `debug.traceTransaction()`. The following information is emitted at each step: - -| field | type | description | -| ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| pc | uint64 | program counter | -| op | byte | opcode to be executed | -| gas | uint64 | remaining gas | -| gasCost | uint64 | cost for executing op | -| memory | []byte | EVM memory. Enabled via `enableMemory` | -| memSize | int | Size of memory | -| stack | []uint256 | EVM stack. Disabled via `disableStack` | -| returnData | []byte | Last call's return data. Enabled via `enableReturnData` | -| storage | map[hash]hash | Storage slots of current contract read from and written to. Only emitted for `SLOAD` and `SSTORE`. Disabled via `disableStorage` | -| depth | int | Current call depth | -| refund | uint64 | Refund counter | -| error | string | Error message if any | - -Note that the fields `memory`, `stack`, `returnData`, and `storage` have dynamic size and depending on the exact transaction they could grow large in size. This is specially true for `memory` which could blow up the trace size. It is recommended to keep them disabled unless they are explicitly required for a given use-case. - -## Native tracers - -The following tracers are implement in Go and as such have offer good performance. They are selected by their name when invoking a tracing API method, e.g. `debug.traceTransaction(, { tracer: 'callTracer' })`. - -### 4byteTracer - -Solidity contract functions are [addressed](https://docs.soliditylang.org/en/develop/abi-spec.html#function-selector) by the first four four byte of the Keccak-256 hash of their signature. Therefore when calling the function of a contract, the caller must send this function selector as well as the ABI-encoded arguments as call data. - -The `4byteTracer` collects the function selectors of every function executed in the lifetime of a transaction, along with the size of the supplied call data. The result is a `map[string]int` where the keys are `SELECTOR-CALLDATASIZE` and the values are number of occurances of this key. E.g.: - -```terminal -> debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"}) -{ - "0x27dc297e-128": 1, - "0x38cc4831-0": 2, - "0x524f3889-96": 1, - "0xadf59f99-288": 1, - "0xc281d19e-0": 1 -} -``` - -### callTracer - -The `callTracer` tracks all the call frames executed during a transaction, including depth 0. The result will be a nested list of call frames, resembling how EVM works. They form a tree with the top-level call at root and sub-calls as children of the higher levels. Each call frame has the following fields: - -| field | type | description | -| ------- | ----------- | ------------------------------------ | -| type | string | CALL or CREATE | -| from | string | address | -| to | string | address | -| value | string | hex-encoded amount of value transfer | -| gas | string | hex-encoded gas provided for call | -| gasUsed | string | hex-encoded gas used during call | -| input | string | call data | -| output | string | return data | -| error | string | error, if any | -| calls | []callframe | list of sub-calls | - -Things to note about the call tracer: - -- Calls to precompiles are also included in the result -- In case a frame reverts, the field `output` will contain the raw return data, unlike [revertReasonTracer](#revertreasontracer) which parses the data and returns the revert message - -### noopTracer - -This tracer is noop. It returns an empty object and is only meant for testing the setup. - -### prestateTracer - -Executing a transaction requires the prior state, including account of sender and recipient, contracts that are called during execution, etc. The `prestateTracer` replays the tx and tracks every part of state that is touched. This is similar to the concept of a [stateless witness](https://ethresear.ch/t/the-stateless-client-concept/172), the difference being this tracer doesn't return any cryptographic proof, rather only the trie leaves. The result is an object. The keys are addresses of accounts. The value is an object with the following fields: - -| field | type | description | -| ------- | ----------------- | ----------------------------- | -| balance | string | balance in Wei | -| nonce | uint64 | nonce | -| code | string | hex-encoded bytecode | -| storage | map[string]string | storage slots of the contract | - -### revertReasonTracer - -The `revertReasonTracer` is useful for analyzing failed transactions. The return value is: - -- In case the transaction reverted: reason of the revert as returned by the Solidity contract -- Error message for any other failure - -Example: - -```terminal -> debug.traceTransaction('0x97695ffb034be7e1faeb372a564bb951ba4ebf4fee4caff2f9d1702497bb2b8b', { tracer: 'revertReasonTracer' }) -"execution reverted: tokensMintedPerAddress exceed MAX_TOKENS_MINTED_PER_ADDRESS" -``` - -## JS tracers - -The following are a list of tracers written in JS that come as part of Geth: - -- `bigramTracer`: Counts the opcode bigrams, i.e. how many times 2 opcodes were executed one after the other -- `evmdisTracer`: Returns sufficient information from a trace to perform [evmdis](https://github.com/Arachnid/evmdis)-style disassembly -- `opcountTracer` Counts the total number of opcodes executed -- `trigramTracer`: Counts the opcode trigrams -- `unigramTracer`: Counts the occurances of each opcode diff --git a/content/docs/developers/dapp-developer/custom-tracer.md b/content/docs/developers/dapp-developer/custom-tracer.md deleted file mode 100644 index a025c87dcd..0000000000 --- a/content/docs/developers/dapp-developer/custom-tracer.md +++ /dev/null @@ -1,410 +0,0 @@ ---- -title: Custom EVM tracer -description: Introduction to writing custom tracers for Geth ---- - -In addition to the default opcode tracer and the built-in tracers, Geth offers the possibility to write custom code that hook to events in the EVM to process and return the data in a consumable format. Custom tracers can be written either in Javascript or Go. JS tracers are good for quick prototyping and experimentation as well as for less intensive applications. Go tracers are performant but require the tracer to be compiled together with the Geth source code. - -## Custom Javascript tracing - -Transaction traces include the complete status of the EVM at every point during the transaction execution, which can be a very large amount of data. Often, users are only interested in a small subset of that data. Javascript trace filters are available to isolate the useful information. Detailed information about `debug_traceTransaction` and its component parts is available in the [reference documentation](/content/docs/developers/interacting-with-geth/rpc/ns-debug#debug_tracetransaction). - -### A simple filter - -Filters are Javascript functions that select information from the trace to persist and discard based on some conditions. The following Javascript function returns only the sequence of opcodes executed by the transaction as a comma-separated list. The function could be written directly in the Javascript console, but it is cleaner to write it in a separate re-usable file and load it into the console. - -1. Create a file, `filterTrace_1.js`, with this content: - - ```javascript - tracer = function (tx) { - return debug.traceTransaction(tx, { - tracer: - '{' + - 'retVal: [],' + - 'step: function(log,db) {this.retVal.push(log.getPC() + ":" + log.op.toString())},' + - 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + - 'result: function(ctx,db) {return this.retVal}' + - '}' - }); // return debug.traceTransaction ... - }; // tracer = function ... - ``` - -2. Run the [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console). -3. Get the hash of a recent transaction from a node or block explorer. - -4. Run this command to run the script: - - ```javascript - loadScript('filterTrace_1.js'); - ``` - -5. Run the tracer from the script. Be patient, it could take a long time. - - ```javascript - tracer(''); - ``` - - The bottom of the output looks similar to: - - ```sh - "3366:POP", "3367:JUMP", "1355:JUMPDEST", "1356:PUSH1", "1358:MLOAD", "1359:DUP1", "1360:DUP3", "1361:ISZERO", "1362:ISZERO", - "1363:ISZERO", "1364:ISZERO", "1365:DUP2", "1366:MSTORE", "1367:PUSH1", "1369:ADD", "1370:SWAP2", "1371:POP", "1372:POP", "1373:PUSH1", - "1375:MLOAD", "1376:DUP1", "1377:SWAP2", "1378:SUB", "1379:SWAP1", "1380:RETURN" - ``` - -6. Run this line to get a more readable output with each string in its own line. - - ```javascript - console.log(JSON.stringify(tracer(''), null, 2)); - ``` - -More information about the `JSON.stringify` function is available [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). - -The commands above worked by calling the same `debug.traceTransaction` function that was previously explained in [basic traces](https://geth.ethereum.org/docs/dapp/tracing), but with a new parameter, `tracer`. This parameter takes the JavaScript object formated as a string. In the case of the trace above, it is: - -```javascript -{ - retVal: [], - step: function(log,db) {this.retVal.push(log.getPC() + ":" + log.op.toString())}, - fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))}, - result: function(ctx,db) {return this.retVal} -} -``` - -This object has three member functions: - -- `step`, called for each opcode. -- `fault`, called if there is a problem in the execution. -- `result`, called to produce the results that are returned by `debug.traceTransaction` after the execution is done. - -In this case, `retVal` is used to store the list of strings to return in `result`. - -The `step` function adds to `retVal` the program counter and the name of the opcode there. Then, in `result`, this list is returned to be sent to the caller. - -### Filtering with conditions - -For actual filtered tracing we need an `if` statement to only log relevant information. For example, to isolate the transaction's interaction with storage, the following tracer could be used: - -```javascript -tracer = function (tx) { - return debug.traceTransaction(tx, { - tracer: - '{' + - 'retVal: [],' + - 'step: function(log,db) {' + - ' if(log.op.toNumber() == 0x54) ' + - ' this.retVal.push(log.getPC() + ": SLOAD");' + - ' if(log.op.toNumber() == 0x55) ' + - ' this.retVal.push(log.getPC() + ": SSTORE");' + - '},' + - 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + - 'result: function(ctx,db) {return this.retVal}' + - '}' - }); // return debug.traceTransaction ... -}; // tracer = function ... -``` - -The `step` function here looks at the opcode number of the op, and only pushes an entry if the opcode is `SLOAD` or `SSTORE` ([here is a list of EVM opcodes and their numbers](https://github.com/wolflo/evm-opcodes)). We could have used `log.op.toString()` instead, but it is faster to compare numbers rather than strings. - -The output looks similar to this: - -```javascript -[ - "5921: SLOAD", - . - . - . - "2413: SSTORE", - "2420: SLOAD", - "2475: SSTORE", - "6094: SSTORE" -] -``` - -### Stack Information - -The trace above reports the program counter (PC) and whether the program read from storage or wrote to it. That alone isn't particularly useful. To know more, the `log.stack.peek` function can be used to peek into the stack. `log.stack.peek(0)` is the stack top, `log.stack.peek(1)` the entry below it, etc. - -The values returned by `log.stack.peek` are Go `big.Int` objects. By default they are converted to JavaScript floating point numbers, so you need `toString(16)` to get them as hexadecimals, which is how 256-bit values such as storage cells and their content are normally represented. - -#### Storage Information - -The function below provides a trace of all the storage operations and their parameters. This gives a more complete picture of the program's interaction with storage. - -```javascript -tracer = function (tx) { - return debug.traceTransaction(tx, { - tracer: - '{' + - 'retVal: [],' + - 'step: function(log,db) {' + - ' if(log.op.toNumber() == 0x54) ' + - ' this.retVal.push(log.getPC() + ": SLOAD " + ' + - ' log.stack.peek(0).toString(16));' + - ' if(log.op.toNumber() == 0x55) ' + - ' this.retVal.push(log.getPC() + ": SSTORE " +' + - ' log.stack.peek(0).toString(16) + " <- " +' + - ' log.stack.peek(1).toString(16));' + - '},' + - 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + - 'result: function(ctx,db) {return this.retVal}' + - '}' - }); // return debug.traceTransaction ... -}; // tracer = function ... -``` - -The output is similar to: - -```javascript -[ - "5921: SLOAD 0", - . - . - . - "2413: SSTORE 3f0af0a7a3ed17f5ba6a93e0a2a05e766ed67bf82195d2dd15feead3749a575d <- fb8629ad13d9a12456", - "2420: SLOAD cc39b177dd3a7f50d4c09527584048378a692aed24d31d2eabeddb7f3c041870", - "2475: SSTORE cc39b177dd3a7f50d4c09527584048378a692aed24d31d2eabeddb7f3c041870 <- 358c3de691bd19", - "6094: SSTORE 0 <- 1" -] -``` - -#### Operation Results - -One piece of information missing from the function above is the result on an `SLOAD` operation. The state we get inside `log` is the state prior to the execution of the opcode, so that value is not known yet. For more operations we can figure it out for ourselves, but we don't have access to the -storage, so here we can't. - -The solution is to have a flag, `afterSload`, which is only true in the opcode right after an `SLOAD`, when we can see the result at the top of the stack. - -```javascript -tracer = function (tx) { - return debug.traceTransaction(tx, { - tracer: - '{' + - 'retVal: [],' + - 'afterSload: false,' + - 'step: function(log,db) {' + - ' if(this.afterSload) {' + - ' this.retVal.push(" Result: " + ' + - ' log.stack.peek(0).toString(16)); ' + - ' this.afterSload = false; ' + - ' } ' + - ' if(log.op.toNumber() == 0x54) {' + - ' this.retVal.push(log.getPC() + ": SLOAD " + ' + - ' log.stack.peek(0).toString(16));' + - ' this.afterSload = true; ' + - ' } ' + - ' if(log.op.toNumber() == 0x55) ' + - ' this.retVal.push(log.getPC() + ": SSTORE " +' + - ' log.stack.peek(0).toString(16) + " <- " +' + - ' log.stack.peek(1).toString(16));' + - '},' + - 'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' + - 'result: function(ctx,db) {return this.retVal}' + - '}' - }); // return debug.traceTransaction ... -}; // tracer = function ... -``` - -The output now contains the result in the line that follows the `SLOAD`. - -```javascript -[ - "5921: SLOAD 0", - " Result: 1", - . - . - . - "2413: SSTORE 3f0af0a7a3ed17f5ba6a93e0a2a05e766ed67bf82195d2dd15feead3749a575d <- fb8629ad13d9a12456", - "2420: SLOAD cc39b177dd3a7f50d4c09527584048378a692aed24d31d2eabeddb7f3c041870", - " Result: 0", - "2475: SSTORE cc39b177dd3a7f50d4c09527584048378a692aed24d31d2eabeddb7f3c041870 <- 358c3de691bd19", - "6094: SSTORE 0 <- 1" -] -``` - -### Dealing With Calls Between Contracts - -So the storage has been treated as if there are only 2256 cells. However, that is not true. Contracts can call other contracts, and then the storage involved is the storage of the other contract. We can see the address of the current contract in `log.contract.getAddress()`. This value is the execution context - the contract whose storage we are using - even when code from another contract is executed (by using -[`CALLCODE` or `DELEGATECALL`](https://docs.soliditylang.org/en/v0.8.14/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries)). - -However, `log.contract.getAddress()` returns an array of bytes. To convert this to the familiar hexadecimal representation of Ethereum addresses, `this.byteHex()` and `array2Hex()` can be used. - -```javascript -tracer = function (tx) { - return debug.traceTransaction(tx, { - tracer: - '{' + - 'retVal: [],' + - 'afterSload: false,' + - 'callStack: [],' + - 'byte2Hex: function(byte) {' + - ' if (byte < 0x10) ' + - ' return "0" + byte.toString(16); ' + - ' return byte.toString(16); ' + - '},' + - 'array2Hex: function(arr) {' + - ' var retVal = ""; ' + - ' for (var i=0; i 0 { - t.env.Cancel() - return - } - - name := op.String() - if _, ok := t.counts[name]; !ok { - t.counts[name] = 0 - } - t.counts[name]++ -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *opcounter) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *opcounter) CaptureExit(output []byte, gasUsed uint64, err error) {} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *opcounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *opcounter) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) {} - -func (*opcounter) CaptureTxStart(gasLimit uint64) {} - -func (*opcounter) CaptureTxEnd(restGas uint64) {} - -// GetResult returns the json-encoded nested list of call traces, and any -// error arising from the encoding or forceful termination (via `Stop`). -func (t *opcounter) GetResult() (json.RawMessage, error) { - res, err := json.Marshal(t.counts) - if err != nil { - return nil, err - } - return res, t.reason -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *opcounter) Stop(err error) { - t.reason = err - atomic.StoreUint32(&t.interrupt, 1) -} -``` - -As can be seen every method of the [EVMLogger interface](https://pkg.go.dev/github.com/ethereum/go-ethereum/core/vm#EVMLogger) needs to be implemented (even if empty). Key parts to notice are the `init()` function which registers the tracer in Geth, the `CaptureState` hook where the opcode counts are incremented and `GetResult` where the result is serialized and delivered. To test this out the source is first compiled with `make geth`. Then in the console it can be invoked through the usual API methods by passing in the name it was registered under: - -```console -> debug.traceTransaction('0x7ae446a7897c056023a8104d254237a8d97783a92900a7b0f7db668a9432f384', { tracer: 'opcounter' }) -{ - ADD: 4, - AND: 3, - CALLDATALOAD: 2, - ... -} -``` diff --git a/content/docs/developers/dapp-developer/mobile.md b/content/docs/developers/dapp-developer/mobile.md deleted file mode 100644 index e15aef4efc..0000000000 --- a/content/docs/developers/dapp-developer/mobile.md +++ /dev/null @@ -1,256 +0,0 @@ ---- -title: Geth for Mobile -description: Introduction to mobile development with Geth ---- - -Embedding clients into mobile devices is an important part of Ethereum's decentralization vision. This is because being able to verify data, follow the chain and submit transactions without relying on centralized intermediaries is critical for censorship resistant access to the network. Doing so on a mobile device is the most convenient route for many users. This relies on Geth running a [light client](/docs/interface/les) on the mobile -device and exposing an API that developers can use to build mobile apps on top of Geth. This page outlines how to download Geth for mobile and how to get started with managing Ethereum accounts in mobile applications. Ethereum mobile development is relatively nascent, but there is an active developer community. For further information on Geth mobile development visit the #mobile channel in the [Geth discord](https://discord.gg/wQdpS5aA). - -## Download and install - -### Android - -#### Android Studio - -Geth for Mobile bundles can be downloaded directly from [the download page](https://geth.ethereum.org/downloads/) and inserted into a project in Android Studio via `File -> New -> New module... -> Import .JAR/.AAR Package`. - -It is also necessary to configure `gradle` to link the mobile library bundle to the application. This can be done by adding a new entry to the `dependencies` section of the `build.gradle` script, pointing it to the module that was just added (named `geth` by default). - -```gradle -dependencies { - // All previous dependencies - compile project(':geth') -} -``` - -#### Manual build - -Geth can also be built it locally using a `make` command. This will create an Android archive called `geth.aar` in the `build/bin` folder that can be imported into Android Studio as described above. - -```shell -$ make android -[...] -Done building. -Import "build/bin/geth.aar" to use the library. -``` - -### iOS - -Geth must be downloaded and built locally for IoS. Building locally is achieved using the `make` command. This will create an iOS XCode framework called `Geth.framework` in the `build/bin` folder that can be imported into XCode as described above. - -```bash -$ make ios -[...] -Done building. -Import "build/bin/Geth.framework" to use the library. -``` - -## Mobile API - -Similarly to the reusable [Go libraries](content/docs/developers/dapp-developer/native-accounts.md), the mobile wrappers focus on three main usage areas: - -- Simplified client side account management -- Remote node interfacing via different transports -- Contract interactions through auto-generated bindings - -The Geth mobile API is broadly equivalent to the [Go API](/content/docs/developers/dapp-developer/native-accounts.md). The source code can be found in the `mobile` section of Geth's -[Github](https://github.com/ethereum/go-ethereum/tree/master/mobile). - -## Mobile Account Management - -Best practise for account management is to do it client-side, with all sensitive information self-contained inside the local application. This ensures the developer/user retains fine-grained control over the access permissions for user-data instead of outsourcing security -to a third party. - -To support this, Geth provides an accounts library that includes the tools required for secure account management via encrypted keystores and passphrase protected accounts, similarly to running a full Geth node. - -### Encrypted keystores - -Access keys to Ethereum accounts should never be stored in plain-text. Instead, they should be stored encrypted so that even if the mobile device is accessed by a malicious third party the keys are still hidden under an additional layer of security. Geth provides a keystore that enables developers to store keys securely using the [`secp256k1` elliptic curve](https://www.secg.org/sec2-v2.pdf), implemented using [`libsecp256k`](https://github.com/bitcoin-core/secp256k1) and wrapped by [Geth accounts](https://godoc.org/github.com/ethereum/go-ethereum/accounts). - -Accounts are stored on disk in the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format. Developers should be aware of these implementation details but are not required to deeply understand the cryptographic primitives in order to use the keystore. - -One thing that should be understood, though, is that the cryptographic primitives underpinning the keystore can operate in _light_ or _standard_ mode. Light mode is computationally cheaper, while standard mode has extra security. Light mode is appropriate for mobile devices, but developers -should be aware that there is a security trade-off. - -- _standard_ needs 256MB memory and 1 second processing on a modern CPU to access a key -- _light_ needs 4MB memory and 100 millisecond processing on a modern CPU to access a key - -### Keystores on Android (Java) - -The encrypted keystore on Android is implemented by the `KeyStore` class from the `org.ethereum.geth` package. The configuration constants are located in the `Geth` abstract class, similarly from the `org.ethereum.geth` package. Hence to do client side account management on Android, two classes should be imported into the Java code: - -```java -import org.ethereum.geth.Geth; -import org.ethereum.geth.KeyStore; -``` - -Then new encrypted keystore can be created via: - -```java -KeyStore ks = new KeyStore("/path/to/keystore", Geth.LightScryptN, Geth.LightScryptP); -``` - -The keystore should be in a location writable by the local mobile application but on-readable for other installed applications such as inside the app's data directory. If the `KeyStore` is created from within a class extending an Android object, access to the `Context.getFilesDir()` method is probably provided via `this.getFilesDir()`, so the keystore path could be set to `this.getFilesDir() + "/keystore"`. - -The last two arguments of the `KeyStore` constructor are the crypto parameters defining how resource-intensive the keystore encryption should be. The choices are `Geth.StandardScryptN, Geth.StandardScryptP`, `Geth.LightScryptN, Geth.LightScryptP` or custom numbers. The _light_ version is recommended. - -### Keystores on iOS (Swift 3) - -The encrypted keystore on iOS is implemented by the `GethKeyStore` class from the `Geth` framework. The configuration constants are located in the same namespace as global variables. Hence to do client side account management on iOS, `Geth` framework should be -imported into the Swift code: - -```swift -import Geth -``` - -Then a new encrypted account manager can be created using: - -```swift -let ks = GethNewKeyStore("/path/to/keystore", GethLightScryptN, GethLightScryptP); -``` - -The keystore folder needs to be in a location writable by the local mobile application but non-readable for other installed applications such as inside the app's document directory. The document directory shopuld be retrievable using -`let datadir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]`, so the keystore path could be `datadir + "/keystore"`. - -The last two arguments of the `GethNewKeyStore` factory method are the crypto parameters defining how resource-intensive the keystore encryption should be. The choices are `GethStandardScryptN, GethStandardScryptP`, `GethLightScryptN, GethLightScryptP` or custom numbers. The _light_ version is recommended. - -### Account lifecycle - -The encyrpted keystore can be used for the entire account lifecycle requirements of a mobile application. This includes the basic functionality of creating new accounts and deleting existing ones as well as more advanced functions like updating access credentials and account -import/export. - -Although the keystore defines the encryption strength it uses to store accounts, there is no global master password that can grant access to all of them. Rather each account is maintained individually, and stored on disk in its [encrypted format][secstore] individually, ensuring a much cleaner and stricter separation of credentials. - -This individuality means that any operation requiring access to an account will need to provide the necessary authentication credentials for that particular account in the form of a passphrase: - -- When creating a new account, the caller must supply a passphrase to encrypt the account with. This passphrase will be required for any subsequent access. -- When deleting an existing account, the caller must supply a passphrase to verify ownership of the account. This isn't cryptographically necessary, rather a protective measure against accidental loss of accounts. -- When updating an existing account, the caller must supply both current and new passphrases. After completing the operation, the account will not be accessible via the old passphrase. -- When exporting an existing account, the caller must supply both the current passphrase to decrypt the account, as well as an export passphrase to re-encrypt it with before returning the key-file to the user. This is required to allow moving accounts between devices without sharing original credentials. -- When importing a new account, the caller must supply both the encryption passphrase of the key-file being imported, as well as a new passphrase with which to store the account. This is required to allow storing account with different credentials than used for moving them around. - -_Please note, there is no recovery mechanisms for losing the passphrases. The cryptographic properties of the encrypted keystore (if using the provided parameters) guarantee that account credentials cannot be brute forced in any meaningful time._ - -### Accounts on Android (Java) - -An Ethereum account on Android is implemented by the `Account` class from the `org.ethereum.geth` package. Assuming an instance of a `KeyStore` called `ks` exists, all of the described lifecycle operations can be executed with a handful of function calls: - -```java -// Create a new account with the specified encryption passphrase. -Account newAcc = ksm.newAccount("Creation password"); - -// Export the newly created account with a different passphrase. The returned -// data from this method invocation is a JSON encoded, encrypted key-file. -byte[] jsonAcc = ks.exportKey(newAcc, "Creation password", "Export password"); - -// Update the passphrase on the account created above inside the local keystore. -ks.updateAccount(newAcc, "Creation password", "Update password"); - -// Delete the account updated above from the local keystore. -ks.deleteAccount(newAcc, "Update password"); - -// Import back the account we've exported (and then deleted) above with yet -// again a fresh passphrase. -Account impAcc = ks.importKey(jsonAcc, "Export password", "Import password"); -``` - -Although instances of `Account` can be used to access various information about specific Ethereum accounts, they do not contain any sensitive data (such as passphrases or private keys), rather they act solely as identifiers for client code and the keystore. - -### Accounts on iOS (Swift 3) - -An Ethereum account on iOS is implemented by the `GethAccount` class from the `Geth` framework. Assuming an instance of a `GethKeyStore` called `ks` exists, all of the described lifecycle operations can be executed with a handful of function calls: - -```swift -// Create a new account with the specified encryption passphrase. -let newAcc = try! ks?.newAccount("Creation password") - -// Export the newly created account with a different passphrase. The returned -// data from this method invocation is a JSON encoded, encrypted key-file. -let jsonKey = try! ks?.exportKey(newAcc!, passphrase: "Creation password", newPassphrase: "Export password") - -// Update the passphrase on the account created above inside the local keystore. -try! ks?.update(newAcc, passphrase: "Creation password", newPassphrase: "Update password") - -// Delete the account updated above from the local keystore. -try! ks?.delete(newAcc, passphrase: "Update password") - -// Import back the account we've exported (and then deleted) above with yet -// again a fresh passphrase. -let impAcc = try! ks?.importKey(jsonKey, passphrase: "Export password", newPassphrase: "Import password") -``` - -Although instances of `GethAccount` can be used to access various information about specific Ethereum accounts, they do not contain any sensitive data (such as passphrases or private keys), rather they act solely as identifiers for client code and the keystore. - -## Signing authorization - -As mentioned above, account objects do not hold the sensitive private keys of the associated Ethereum accounts - they are merely placeholders to identify the cryptographic keys with. All operations that require authorization (e.g. transaction signing) are performed by the account manager after granting it access to the private keys. - -There are a few different ways one can authorize the account manager to execute signing operations. Since the different methods have very different security guarantees, it is essential to be clear on how each works: - -- **Single authorization**: The simplest way to sign a transaction via the keystore is to provide the passphrase of the account every time something needs to be signed, which will ephemerally decrypt the private key, execute the signing operation and immediately throw away the decrypted key. The drawbacks are that the passphrase needs to be queried from the user every time, which can become annoying if done frequently; or the application needs to keep the passphrase in memory, which can have security consequences if not done properly; and depending on the keystore's configured strength, constantly decrypting keys can result in non-negligible resource requirements. - -- **Multiple authorizations**: A more complex way of signing transactions via the keystore is to unlock the account via its passphrase once, and allow the account manager to cache the decrypted private key, enabling all subsequent signing requests tocomplete without the passphrase. The lifetime of the cached private key may be managed manually (by explicitly locking the account back up) or automatically (by providing a timeout during unlock). This mechanism is useful for scenarios where the user may need to sign many transactions or the application would need to do so without requiring user input. The crucial aspect to remember is that **anyone with access to the account manager can sign transactions while a particular account is unlocked** (e.g. device left unattended; application running untrusted code). - -### Signing on Android (Java) - -Assuming an instance of a `KeyStore` called `ks` exists, a new account to sign transactions can be created using its `newAccount` method. For this demonstation a hard-coded example transaction is created to sign: - -```java -// Create a new account to sign transactions with -Account signer = ks.newAccount("Signer password"); -Transaction tx = new Transaction( - 1, new Address("0x0000000000000000000000000000000000000000"), - new BigInt(0), new BigInt(0), new BigInt(1), null); // Random empty transaction -BigInt chain = new BigInt(1); // Chain identifier of the main net -``` - -The transaction `tx` can be signed using the authorization mechanisms described above: - -```java -// Sign a transaction with a single authorization -Transaction signed = ks.signTxPassphrase(signer, "Signer password", tx, chain); - -// Sign a transaction with multiple manually cancelled authorizations -ks.unlock(signer, "Signer password"); -signed = ks.signTx(signer, tx, chain); -ks.lock(signer.getAddress()); - -// Sign a transaction with multiple automatically cancelled authorizations -ks.timedUnlock(signer, "Signer password", 1000000000); -signed = ks.signTx(signer, tx, chain); -``` - -### Signing on iOS (Swift 3) - -Assuming an instance of a `GethKeyStore` called `ks` exists, a new account can be created to sign transactions with its `newAccount` method. For -this demonstation a hard-coded example transaction is created to sign: - -```swift -// Create a new account to sign transactions with -var error: NSError? -let signer = try! ks?.newAccount("Signer password") - -let to = GethNewAddressFromHex("0x0000000000000000000000000000000000000000", &error) -let tx = GethNewTransaction(1, to, GethNewBigInt(0), GethNewBigInt(0), GethNewBigInt(0), nil) // Random empty transaction -let chain = GethNewBigInt(1) // Chain identifier of the main net -``` - -The transaction `tx` can now be signed using the authorization methods described above: - -```swift -// Sign a transaction with a single authorization -var signed = try! ks?.signTxPassphrase(signer, passphrase: "Signer password", tx: tx, chainID: chain) - -// Sign a transaction with multiple manually cancelled authorizations -try! ks?.unlock(signer, passphrase: "Signer password") -signed = try! ks?.signTx(signer, tx: tx, chainID: chain) -try! ks?.lock(signer?.getAddress()) - -// Sign a transaction with multiple automatically cancelled authorizations -try! ks?.timedUnlock(signer, passphrase: "Signer password", timeout: 1000000000) -signed = try! ks?.signTx(signer, tx: tx, chainID: chain) -``` - -## Summary - -This page introduced Geth for mobile. In addition to download and installation instructions, basic account management was demonstrated for mobile applications on iOS and Android. diff --git a/content/docs/developers/dapp-developer/native-accounts.md b/content/docs/developers/dapp-developer/native-accounts.md deleted file mode 100644 index 813c7b86a0..0000000000 --- a/content/docs/developers/dapp-developer/native-accounts.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: Go Account Management -description: Introduction to account management in Go native applications. ---- - -Geth provides a simple, yet thorough accounts package that includes all the tools developers need to leverage all the security of Geth's crypto implementation in a Go native application. The account management is done client side with all sensitive data held inside the application. This gives the user control over access permissions without relying on any third party. - -**Note Geth's built-in account management is convenient and straightforward to use, but best practise is to use the external tool _Clef_ for key management.** - -## Encrypted keystores - -Access keys to Ethereum accounts should never be stored in plain-text. Instead, they should be stored encrypted so that even if the mobile device is accessed by a malicious third party the keys are still hidden under an additional layer of security. Geth provides a keystore that enables developers to store keys securely. The Geth keystore uses [Scrypt](https://pkg.go.dev/golang.org/x/crypto/scrypt) to store keys that are encoded using the [`secp256k1`](https://www.secg.org/sec2-v2.pdf) elliptic curve. Accounts are stored on disk in the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format. Developers should be aware of these implementation details -but are not required to deeply understand the cryptographic primitives in order to use the keystore. - -One thing that should be understood, though, is that the cryptographic primitives underpinning the keystore can operate in light or standard mode.Light mode is computationally cheaper, while standard mode has extra security. Light mode is appropriate for mobile devices, but developers should be aware that there is a security trade-off. - -- standard needs 256MB memory and 1 second processing on a modern CPU to access a key -- light needs 4MB memory and 100 millisecond processing on a modern CPU to access a key - -The encrypted keystore is implemented by the [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) struct from the [`accounts`](https://godoc.org/github.com/ethereum/go-ethereum/accounts) package, which also contains the configuration constants for the _standard_ or _light_ security modes described above. Hence client side account management -simply requires importing the `accounts` package into the application code. - -```go -import "github.com/ethereum/go-ethereum/accounts" -import "github.com/ethereum/go-ethereum/accounts/keystore" -import "github.com/ethereum/go-ethereum/common" -``` - -Afterwards a new encrypted account manager can be created via: - -```go -ks := keystore.NewKeyStore("/path/to/keystore", keystore.StandardScryptN, keystore.StandardScryptP) -am := accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: false}, ks) -``` - -The path to the keystore folder needs to be a location that is writable by the local user but non-readable for other system users, such as inside the user's home directory. - -The last two arguments of [`keystore.NewKeyStore`](https://godoc.org/github.com/ethereum/go-ethereum/accounts/keystore#NewKeyStore) are the crypto parameters defining how resource-intensive the keystore encryption should be. The options are [`accounts.StandardScryptN, accounts.StandardScryptP`, `accounts.LightScryptN, accounts.LightScryptP`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#pkg-constants) or custom values (requiring understanding of the underlying cryptography). The _standard_ version is recommended. - -## Account lifecycle - -Once an encrypted keystore for Ethereum accounts exists it, it can be used to manage accounts for the entire account lifecycle requirements of a Go native application. This includes the basic functionality of creating new accounts and deleting existing ones as well as updating access credentials, exporting existing accounts, and importing them on other devices. - -Although the keystore defines the encryption strength it uses to store accounts, there is no global master password that can grant access to all of them. Rather each account is maintained individually, and stored on disk in its [encrypted format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) individually, ensuring a much cleaner and stricter separation of credentials. - -This individuality means that any operation requiring access to an account will need to provide the necessary authentication credentials for that particular account in the form of a passphrase: - -- When creating a new account, the caller must supply a passphrase to encrypt the account with. This passphrase will be required for any subsequent access, the lack of which will forever forfeit using the newly created account. - -- When deleting an existing account, the caller must supply a passphrase to verify ownership of the account. This isn't cryptographically necessary, rather a protective measure against accidental loss of accounts. - -- When updating an existing account, the caller must supply both current and new passphrases. After completing the operation, the account will not be accessible via the old passphrase any more. - -- When exporting an existing account, the caller must supply both the current passphrase to decrypt the account, as well as an export passphrase to re-encrypt it with before returning the key-file to the user. This is required to allow moving accounts between machines and applications without sharing original credentials. - -- When importing a new account, the caller must supply both the encryption passphrase of the key-file being imported, as well as a new passhprase with which to store the account. This is required to allow storing account with different credentials than used for moving them around. - -**_Please note, there are no recovery mechanisms for lost passphrases. The cryptographic properties of the encrypted keystore (using the provided parameters) guarantee that account credentials cannot be brute forced in any meaningful time._** - -An Ethereum account is implemented by the [`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account) struct from the Geth [accounts](https://godoc.org/github.com/ethereum/go-ethereum/accounts) package. Assuming an instance of an [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) called `am` exists, all of the described lifecycle operations can be executed with a handful of function calls (error handling omitted). - -```go -// Create a new account with the specified encryption passphrase. -newAcc, _ := ks.NewAccount("Creation password") -fmt.Println(newAcc) - -// Export the newly created account with a different passphrase. The returned -// data from this method invocation is a JSON encoded, encrypted key-file. -jsonAcc, _ := ks.Export(newAcc, "Creation password", "Export password") - -// Update the passphrase on the account created above inside the local keystore. -_ = ks.Update(newAcc, "Creation password", "Update password") - -// Delete the account updated above from the local keystore. -_ = ks.Delete(newAcc, "Update password") - -// Import back the account we've exported (and then deleted) above with yet -// again a fresh passphrase. -impAcc, _ := ks.Import(jsonAcc, "Export password", "Import password") -``` - -_Although instances of [`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account) can be used to access various information about specific Ethereum accounts, they do not contain any sensitive data (such as passphrases or private keys), rather they act solely as identifiers for client code and the keystore._ - -## Signing authorization - -Account objects do not hold the sensitive private keys of the associated Ethereum accounts. Account objects are placeholders that identify the cryptographic keys. All operations that require authorization (e.g. transaction signing) are performed by the account manager after granting it access to the private keys. - -There are a few different ways to authorize the account manager to execute signing operations, each having its advantages and drawbacks. Since the different methods have wildly different security guarantees, it is essential to be clear on how each works: - -- **Single authorization**: The simplest way to sign a transaction via the account manager is to provide the passphrase of the account every time something needs to be signed, which will ephemerally decrypt the private key, execute the signing operation and immediately throw away the decrypted key. The drawbacks are that the passphrase needs to be queried from the user every time, which can become annoying if done frequently or the application needs to keep the passphrase in memory, which can have security consequences if not done properly. Depending on the keystore's configured strength, constantly decrypting keys can result in non-negligible resource requirements. - -- **Multiple authorizations**: A more complex way of signing transactions via the account manager is to unlock the account via its passphrase once, and allow the account manager to cache the decrypted private key, enabling all subsequent signing requests to complete without the passphrase. The lifetime of the cached private key may be managed manually (by explicitly locking the account back up) or automatically (by providing a timeout during unlock). This mechanism is useful for scenarios where the user may need to sign many transactions or the application would need to do so without requiring user input. The crucial aspect to remember is that **anyone with access to the account manager can sign transactions while a particular account is unlocked** (e.g. application running untrusted code). - -Assuming an instance of an [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) called `am` exists, a new account can be created to sign transactions using [`NewAccount`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.NewAccount). Creating transactions is out of scope for this page so instead a random [`common.Hash`](https://godoc.org/github.com/ethereum/go-ethereum/common#Hash) will be signed instead. - -For information on creating transactions in Go native applications see the [Go API page](/docs/dapp/native). - -```go -// Create a new account to sign transactions with -signer, _ := ks.NewAccount("Signer password") -txHash := common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") -``` - -With the boilerplate out of the way, the transaction can be signed using the authorization mechanisms described above: - -```go -// Sign a transaction with a single authorization -signature, _ := ks.SignHashWithPassphrase(signer, "Signer password", txHash.Bytes()) - -// Sign a transaction with multiple manually cancelled authorizations -_ = ks.Unlock(signer, "Signer password") -signature, _ = ks.SignHash(signer, txHash.Bytes()) -_ = ks.Lock(signer.Address) - -// Sign a transaction with multiple automatically cancelled authorizations -_ = ks.TimedUnlock(signer, "Signer password", time.Second) -signature, _ = ks.SignHash(signer, txHash.Bytes()) -``` - -Note that [`SignWithPassphrase`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.SignWithPassphrase) takes an [`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account) as the signer, whereas [`Sign`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign) takes only a [`common.Address`](https://godoc.org/github.com/ethereum/go-ethereum/common#Address). The reason for this is that an [`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account) object may also contain a custom key-path, allowing [`SignWithPassphrase`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.SignWithPassphrase) to sign using accounts outside of the keystore; however [`Sign`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.Sign) relies on accounts already unlocked within the keystore, so it cannot specify custom paths. - -## Summary - -Account management is a fundamental pillar of Ethereum development. Geth's Go API provides the tools required to integrate best-practise account security into Go native applications using a simple set of Go functions. diff --git a/content/docs/developers/dapp-developer/native-bindings.md b/content/docs/developers/dapp-developer/native-bindings.md deleted file mode 100644 index e56bde9c6c..0000000000 --- a/content/docs/developers/dapp-developer/native-bindings.md +++ /dev/null @@ -1,530 +0,0 @@ ---- -title: Go Contract Bindings -description: Intriduction to generating bindings for using Geth features in Go native applications ---- - -This page introduces the concept of server-side native dapps. Geth provides the tools required to generate [Go](https://github.com/golang/go/wiki#getting-started-with-go) language bindings to any Ethereum contract that is compile-time type safe, highly performant and can be generated completely automatically from a compiled contract. - -Interacting with a contract on the Ethereum blockchain from Go is already possible via the RPC interfaces exposed by Ethereum clients. However, writing the boilerplate code that translates Go language constructs into RPC calls and back is time consuming and brittle - implementation bugs can only be detected during runtime and it's almost impossible to evolve a contract as even a tiny change in Solidity is awkward to port over to Go. Therefore, Geth provides tools for easily converting contract code into Go code that can be used directly in Go applications. - -This page provides an introduction to generating Go contract bindings and using them in a simple Go application. - -## Prerequisites - -This page is fairly beginner-friendly and designed for people starting out with writing Go native dapps. The core concepts will be introduced gradually as a developer would encounter them. However, some basic familiarity with [Ethereum](https://ethereum.org), [Solidity](https://docs.soliditylang.org/en/v0.8.15/) and [Go](https://go.dev/) is assumed. - -## What is an ABI? - -Ethereum smart contracts have a schema that defines its functions and return types in the form of a JSON file. This JSON file is known as an _Application Binary Interface_, or ABI. The ABI acts as a specification for precisely how to encode data sent to a contract and how to decode the data the contract sends back. The ABI is the only essential piece of information required to generate Go bindings. Go developers can then use the bindings to interact with the contract from their Go application without having to deal directly with data encoding and decoding. An ABI is generated when a contract is compiled. - -## Abigen: Go binding generator - -Geth includes a source code generator called `abigen` that can convert Ethereum ABI definitions into easy to use, type-safe Go packages. With a valid Go development environment set up and the go-ethereum repository checked out correctly, `abigen` can be built as follows: - -``` -$ cd $GOPATH/src/github.com/ethereum/go-ethereum -$ go build ./cmd/abigen -``` - -### Generating the bindings - -To demonstrate the binding generator a contract is required. The contract `Storage.sol` implements two very simple functions: `store` updates a user-defined `uint256` to the contract's storage, and `retrieve` displays the value stored in the contract to the user. The Solidity code is as follows: - -```solidity -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >0.7.0 < 0.9.0; -/** -* @title Storage -* @dev store or retrieve variable value -*/ - -contract Storage { - - uint256 value; - - function store(uint256 number) public{ - value = number; - } - - function retrieve() public view returns (uint256){ - return value; - } -} -``` - -This contract can be pasted into a text file and saved as `Storage.sol`. - -The following code snippet shows how an ABI can be generated for `Storage.sol` using the Solidity compiler `solc`. - -```shell -solc --abi Storage.sol -o build -``` - -The ABI can also be generated in other ways such as using the `compile` commands in development frameworks such as [Truffle](https://trufflesuite.com/docs/truffle/), [Hardhat](https://hardhat.org/) and [Brownie](https://eth-brownie.readthedocs.io/en/stable/) or in the online IDE [Remix](https://remix.ethereum.org/). ABIs for existing verified contracts can be downloaded from [Etherscan](etherscan.io). - -The ABI for `Storage.sol` (`Storage.abi`) looks as follows: - -```json -[ - { - "inputs": [], - "name": "retrieve", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "number", "type": "uint256" }], - "name": "store", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] -``` - -The contract binding can then be generated by passing the ABI to `abigen` as follows: - -``` -$ abigen --abi Storage.abi --pkg main --type Storage --out Storage.go -``` - -Where the flags are: - -- `--abi`: Mandatory path to the contract ABI to bind to -- `--pkg`: Mandatory Go package name to place the Go code into -- `--type`: Optional Go type name to assign to the binding struct -- `--out`: Optional output path for the generated Go source file (not set = stdout) - -This will generate a type-safe Go binding for the Storage contract. The generated code will look something like the snippet below, the full version of which can be viewed [here](https://gist.github.com/jmcook1186/a78e59d203bb54b06e1b81f2cda79d93). - -```go -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package main - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// StorageMetaData contains all meta data concerning the Storage contract. -var StorageMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"retrieve\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} - -// StorageABI is the input ABI used to generate the binding from. -// Deprecated: Use StorageMetaData.ABI instead. -var StorageABI = StorageMetaData.ABI - -// Storage is an auto generated Go binding around an Ethereum contract. -type Storage struct { - StorageCaller // Read-only binding to the contract - StorageTransactor // Write-only binding to the contract - StorageFilterer // Log filterer for contract events -} -... - -``` - -`Storage.go` contains all the bindings required to interact with `Storage.sol` from a Go application. However, this isn't very useful unless the contract is actually deployed on Ethereum or one of Ethereum's testnets. The following sections will demonstrate how to deploy the contract to -an Ethereum testnet and interact with it using the Go bindings. - -### Deploying contracts to Ethereum - -In the previous section, the contract ABI was sufficient for generating the contract bindings from its ABI. However, deploying the contract requires some additional information in the form of the compiled bytecode. - -The bytecode is obtained by running the compiler again but this passing the `--bin` flag, e.g. - -```shell -solc --bin Storage.sol -o Storage.bin -``` - -Then `abigen` can be run again, this time passing `Storage.bin`: - -``` -$ abigen --abi Storage.abi --pkg main --type Storage --out Storage.go --bin Storage.bin -``` - -This will generate something similar to the bindings generated in the previous section. However, an additional `DeployStorage` function has been injected: - -```go -// DeployStorage deploys a new Ethereum contract, binding an instance of Storage to it. -func DeployStorage(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Storage, error) { - parsed, err := StorageMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(StorageBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &Storage{StorageCaller: StorageCaller{contract: contract}, StorageTransactor: StorageTransactor{contract: contract}, StorageFilterer: StorageFilterer{contract: contract}}, nil -} -``` - -View the full file [here](https://gist.github.com/jmcook1186/91124cfcbc7f22dcd3bb4f148d2868a8). - -The new `DeployStorage()` function can be used to deploy the contract to an Ethereum testnet from a Go application. To do this requires incorporating the bindings into a Go application that also handles account management, authorization and Ethereum backend to deploy the contract through. Specifically, this requires: - -1. A running Geth node connected to an Ethereum testnet (recommended Goerli) -2. An account in the keystore prefunded with enough ETH to cover gas costs for deploying and interacting with the contract - -Assuming these prerequisites exist, a new `ethclient` can be instantiated with the local Geth node's ipc file, providing access to the testnet from the Go application. The key can be instantiated as a variable in the application by copying the JSON object from the keyfile in the keystore. - -Putting it all together would result in: - -```go -package main - -import ( - "fmt" - "log" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/ethclient" - -) - -const key = `<>` - -func main() { - // Create an IPC based RPC connection to a remote node and an authorized transactor - conn, err := rpc.NewIPCClient("/home/go-ethereum/goerli/geth.ipc") - if err != nil { - log.Fatalf("Failed to connect to the Ethereum client: %v", err) - } - auth, err := bind.NewTransactor(strings.NewReader(key), "<>") - if err != nil { - log.Fatalf("Failed to create authorized transactor: %v", err) - } - // Deploy the contract passing the newly created `auth` and `conn` vars - address, tx, instance, err := DeployStorage(auth, conn), new(big.Int), "Storage contract in Go!", 0, "Go!") - if err != nil { - log.Fatalf("Failed to deploy new storage contract: %v", err) - } - fmt.Printf("Contract pending deploy: 0x%x\n", address) - fmt.Printf("Transaction waiting to be mined: 0x%x\n\n", tx.Hash()) - - time.Sleep(250 * time.Millisecond) // Allow it to be processed by the local node :P - - // function call on `instance`. Retrieves pending name - name, err := instance.Name(&bind.CallOpts{Pending: true}) - if err != nil { - log.Fatalf("Failed to retrieve pending name: %v", err) - } - fmt.Println("Pending name:", name) -} -``` - -Running this code requests the creation of a brand new `Storage` contract on the Goerli blockchain. The contract functions can be called while the contract is waiting to be included in a block. - -``` -Contract pending deploy: 0x46506d900559ad005feb4645dcbb2dbbf65e19cc -Transaction waiting to be mined: 0x6a81231874edd2461879b7280ddde1a857162a744e3658ca7ec276984802183b - -Pending name: Storage contract in Go! -``` - -Once the contract deployment has been included in a validated block, the contract exists permanently at its deployment address and can now be interacted with from other applications without ever needing to be redeployed. - -Note that `DeployStorage` returns four variables: - -- `address`: the deployment address of the contract - -- `tx`: the transaction hash that can be queried using Geth or a service like [Etherscan](etherscan.io) - -- `instance`: an instance of the deployed contract whose functions can be called in the Go application - -- `err`: a variable that handles errors in case of a deployment failure - -### Accessing an Ethereum contract - -To interact with a contract already deployed on the blockchain, the deployment `address` is required and a `backend` through which to access Ethereum must be defined. The binding generator provides an RPC backend out-of-the-box that can be used to attach to an existing Ethereum node via IPC, HTTP or WebSockets. - -As in the previous section, a Geth node running on an Ethereum testnet (recommend Goerli) and an account with some test ETH to cover gas is required. The `Storage.sol` deployment address is also needed. - -Again, an instance of `ethclient` can be created, passing the path to Geth's ipc file. In the example below this backend is assigned to the variable `conn`. - -```go -// Create an IPC based RPC connection to a remote node -// NOTE update the path to the ipc file! -conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") -if err != nil { - log.Fatalf("Failed to connect to the Ethereum client: %v", err) -} -``` - -The functions available for interacting with the `Storage` contract are defined in `Storage.go`. To create a new instance of the contract in a Go application, the `NewStorage()` function can be used. The function is defined in `Storage.go` as follows: - -```go -// NewStorage creates a new instance of Storage, bound to a specific deployed contract. -func NewStorage(address common.Address, backend bind.ContractBackend) (*Storage, error) { - contract, err := bindStorage(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Storage{StorageCaller: StorageCaller{contract: contract}, StorageTransactor: StorageTransactor{contract: contract}, StorageFilterer: StorageFilterer{contract: contract}}, nil -} -``` - -`NewStorage()` takes two arguments: the deployment address and a backend (`conn`) and returns an instance of the deployed contract. In the example below, the instance is assigned to `store`. - -```go -package main - -import ( - "fmt" - "log" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" -) - -func main() { - // Create an IPC based RPC connection to a remote node - // NOTE update the path to the ipc file! - conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") - if err != nil { - log.Fatalf("Failed to connect to the Ethereum client: %v", err) - } - // Instantiate the contract and display its name - // NOTE update the deployment address! - store, err := NewStorage(common.HexToAddress("0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576"), conn) - if err != nil { - log.Fatalf("Failed to instantiate Storage contract: %v", err) - } - -``` - -The contract instance is then available to interact with in the Go application. To read a value from the blockchain, for example the `value` stored in the contract, the contract's `Retrieve()` function can be called. Again, the function is defined in `Storage.go` as follows: - -```go -// Retrieve is a free data retrieval call binding the contract method 0x2e64cec1. -// -// Solidity: function retrieve() view returns(uint256) -func (_Storage *StorageCaller) Retrieve(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Storage.contract.Call(opts, &out, "retrieve") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} -``` - -Note that the `Retrieve()` function requires a parameter to be passed, even though the original Solidity contract didn't require any at all none. The parameter required is a `*bind.CallOpts` type, which can be used to fine tune the call. If no adjustments to the call are required, pass `nil`. Adjustments to the call include: - -- `Pending`: Whether to access pending contract state or the current stable one -- `GasLimit`: Place a limit on the computing resources the call might consume - -So to call the `Retrieve()` function in the Go application: - -```go -value, err := store.Retrieve(nil) -if err != nil { - log.Fatalf("Failed to retrieve value: %v", err) -} -fmt.Println("Value: ", value) -} -``` - -The output will be something like: - -```terminal -Value: 56 -``` - -### Transacting with an Ethereum contract - -Invoking a method that changes contract state (i.e. transacting) is a bit more involved, as a live transaction needs to be authorized and broadcast into the network. **Go bindings require local signing of transactions and do not delegate this to a remote node.** This is to keep accounts private within dapps, and not shared (by default) between them. - -Thus to allow transacting with a contract, your code needs to implement a method that given an input transaction, signs it and returns an authorized output transaction. Since most users have their keys in the [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) format, the `bind` package contains a small utility method (`bind.NewTransactor(keyjson, passphrase)`) that can create an authorized transactor from a key file and associated password, without the user needing to implement key signing themselves. - -Changing the previous code snippet to update the value stored in the contract: - -```go -package main - -import ( - "fmt" - "log" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" -) - -const key = `json object from keystore` - -func main() { - // Create an IPC based RPC connection to a remote node and instantiate a contract binding - conn, err := ethclient.Dial("/home/go-ethereum/goerli/geth.ipc") - if err != nil { - log.Fatalf("Failed to connect to the Ethereum client: %v", err) - } - store, err := NewStorage(common.HexToAddress("0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576"), conn) - if err != nil { - log.Fatalf("Failed to instantiate a Storage contract: %v", err) - } - // Create an authorized transactor and call the store function - auth, err := bind.NewStorageTransactor(strings.NewReader(key), "strong_password") - if err != nil { - log.Fatalf("Failed to create authorized transactor: %v", err) - } - // Call the store() function - tx, err := store.Store(auth, big.NewInt(420)) - if err != nil { - log.Fatalf("Failed to update value: %v", err) - } - fmt.Printf("Update pending: 0x%x\n", tx.Hash()) -} -``` - -And the output: - -```terminal -Update pending: 0x4f4aaeb29ed48e88dd653a81f0b05d4df64a86c99d4e83b5bfeb0f0006b0e55b -``` - -Similar to the method invocations in the previous section which only read contract state, transacting methods also require a mandatory first parameter, a `*bind.TransactOpts` type, which authorizes the transaction and potentially fine tunes it: - -- `From`: Address of the account to invoke the method with (mandatory) -- `Signer`: Method to sign a transaction locally before broadcasting it (mandatory) -- `Nonce`: Account nonce to use for the transaction ordering (optional) -- `GasLimit`: Place a limit on the computing resources the call might consume (optional) -- `GasPrice`: Explicitly set the gas price to run the transaction with (optional) -- `Value`: Any funds to transfer along with the method call (optional) - -The two mandatory fields are automatically set by the `bind` package if the auth options are constructed using `bind.NewTransactor`. The nonce and gas related fields are automatically derived by the binding if they are not set. Unset values are assumed to be zero. - -### Pre-configured contract sessions - -Reading and state modifying contract-calls require a mandatory first parameter which can authorize and fine tune some of the internal parameters. However, most of the time the same accounts and parameters will be used to issue many transactions, so constructing the call/transact options individually quickly becomes unwieldy. - -To avoid this, the generator also creates specialized wrappers that can be pre-configured with tuning and authorization parameters, allowing all the Solidity defined methods to be invoked without needing an extra parameter. - -These are named similarly to the original contract type name but suffixed with `Sessions`: - -```go -// Wrap the Storage contract instance into a session -session := &StorageSession{ - Contract: store, - CallOpts: bind.CallOpts{ - Pending: true, - }, - TransactOpts: bind.TransactOpts{ - From: auth.From, - Signer: auth.Signer, - GasLimit: big.NewInt(3141592), - }, -} -// Call the previous methods without the option parameters -session.Store(big.NewInt(69)) -``` - -## Bind Solidity directly - -In the past, abigen allowed compilation and binding of a Solidity source file directly to a Go package in a single step. This feature has been discontinued from [v1.10.18](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.18) onwards due to maintenance synchronization challenges with the compiler in Geth. - -The compilation and binding steps can be joined together into a pipeline, for example: - -``` -solc Storage.sol --combined-json abi,bin | abigen --pkg main --type storage --out Storage.go --combined-json - -``` - -### Project integration (`go generate`) - -The `abigen` command was made in such a way as to integrate easily into existing Go toolchains: instead of having to remember the exact command needed to bind an Ethereum contract into a Go project, `go generate` can handle all the fine details. - -Place the binding generation command into a Go source file before the package definition: - -``` -//go:generate abigen --sol Storage.sol --pkg main --out Storage.go -``` - -After which whenever the Solidity contract is modified, instead of needing to remember and run the above command, we can simply call `go generate` on the package (or even the entire source tree via `go generate ./...`), and it will correctly generate the new bindings for us. - -## Blockchain simulator - -Being able to deploy and access deployed Ethereum contracts from native Go code is a powerful feature. However, using public testnets as a backend does not lend itself well to _automated unit testing_. Therefore, Geth also implements a _simulated blockchain_ that can be set as a backend to native contracts the same way as a live RPC backend, using the command `backends.NewSimulatedBackend(genesisAccounts)`. The code snippet below shows how this can be used as a backend in a Go application. - -```go -package main - -import ( - "fmt" - "log" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/crypto" -) - -func main() { - // Generate a new random account and a funded simulator - key, _ := crypto.GenerateKey() - auth := bind.NewKeyedTransactor(key) - - sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) - - // instantiate contract - store, err := NewStorage(common.HexToAddress("0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576"), sim) - if err != nil { - log.Fatalf("Failed to instantiate a Storage contract: %v", err) - } - // Create an authorized transactor and call the store function - auth, err := bind.NewStorageTransactor(strings.NewReader(key), "strong_password") - if err != nil { - log.Fatalf("Failed to create authorized transactor: %v", err) - } - // Call the store() function - tx, err := store.Store(auth, big.NewInt(420)) - if err != nil { - log.Fatalf("Failed to update value: %v", err) - } - fmt.Printf("Update pending: 0x%x\n", tx.Hash()) -} -``` - -## Summary - -To make interacting with Ethereum contracts easier for Go developers, Geth provides tools that generate contract bindings automatically. This makes contract functions available in Go native applications. diff --git a/content/docs/developers/dapp-developer/native.md b/content/docs/developers/dapp-developer/native.md deleted file mode 100644 index 130f8e6ea4..0000000000 --- a/content/docs/developers/dapp-developer/native.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -title: Go API -description: Introduction to the Go packages that allow Geth to be used in Go native applications. ---- - -Ethereum was originally conceptualized to be the base layer for [Web3](https://ethereum.org/en/web3/), providing the backbone for a new generation of decentralized, permissionless and censorship resistant applications called [dapps](https://ethereum.org/en/glossary/#dapp). The first step towards this vision was the development of clients providing an RPC interface into the peer-to-peer protocols. This allowed users to transact between accounts and interact with smart contracts using command line tools. Geth was one of the original clients to provide this type of gateway to the Ethereum network. - -Before long, web-browser-like graphical interfaces (e.g. Mist) were created to extend clients, and client functions were built into websites built using the time-tested HTML/CSS/JS stack. However, to support the most diverse, complex dapps, developers require programmatic access to client functions through an API. This opens up client technologies as re-usable, composable units that can be applied in creative ways by a global community of developers. - -To support this, Geth ships official Go packages that can be embedded into third party desktop and server applications. There is also a [mobile API](/content/docs/developers/dapp-developer/mobile.md) that can be used to embed Geth into mobile applications. - -This page provides a high-level overview of the Go API. - -_Note, this guide will assume some familiarity with Go development. It does not cover general topics about Go project layouts, import paths or any other standard methodologies. If you are new to Go, consider reading [Getting Started with Go](https://github.com/golang/go/wiki#getting-started-with-go) first._ - -## Overview - -Geth's reusable Go libraries focus on three main usage areas: - -- Simplified client side account management -- Remote node interfacing via different transports -- Contract interactions through auto-generated bindings - -The libraries are updated synchronously with the Geth Github repository. The Go libraries can be viewed in full at [Go Packages](https://pkg.go.dev/github.com/ethereum/go-ethereum#section-directories). - -Péter Szilágyi (@karalabe) gave a high level overview of the Go libraries in a talk at DevCon2 in Shanghai in 2016. The slides are still a useful resource ([available here](https://ethereum.karalabe.com/talks/2016-devcon.html)) and the talk itself can be viewed by clicking the image below (it is also archived on [IPFS](https://ipfs.io/ipfs/QmQRuKPKWWJAamrMqAp9rytX6Q4NvcXUKkhvu3kuREKqXR)). - -[![Peter's Devcon2 talk](/assets/devcon2_labelled.webp)](https://www.youtube.com/watch?v=R0Ia1U9Gxjg) - -## Go packages - -The `go-ethereum` library is distributed as a collection of standard Go packages straight from go-ethereum's GitHub repository. The packages can be used directly via the official Go toolkit, without needing any third party tools. - -The canonical import path for Geth is `github.com/ethereum/go-ethereum`, with all packages residing underneath. Although there are [lots of them](https://pkg.go.dev/github.com/ethereum/go-ethereum/#section-directories) most developers will only care about a limited subset. - -All the Geth packages can be downloaded using: - -``` -$ go get -d github.com/ethereum/go-ethereum/... -``` - -More Go API support for dapp developers can be found on the [Go Contract Bindings](/content/docs/developers/dapp-developer/native-bindings.md) and [Go Account Management](/docs/dapp/native-accounts) pages. - -## Tutorial - -This section includes some basic usage examples for the `ethclient` and `gethclient` packages available as part of the Go API. The `ethclient` package provides a client that implements the full Ethereum JSON-RPC API, whereas `gethclient` offers the Geth-specific API. - -### Instantiating a client - -The client is an instance of the `Client` struct which has associated functions that wrap requests to the Ethereum or Geth RPC API endpoints. - -A client is instantiated by passing a raw url or path to an ipc file to the client's `Dial` function. In the following code snippet the path to the ipc file for a local Geth node is provided to `ethclient.Dial()`. - -```go -// create instance of ethclient and assign to cl -cl, err := ethclient.Dial("/tmp/geth.ipc") -if err != nil { - panic(err) -} -_ = cl -``` - -### Interacting with the client - -The client can now be used to handle requests to the Geth node using the full JSON-RPC API. For example, the function `BlockNumer()` wraps a call to the `eth_blockNumber` endpoint. The function `SendTransaction` wraps a call to `eth_sendTransaction`. The full list of client methods can be found [here](https://pkg.go.dev/github.com/ethereum/go-ethereum/ethclient#Client). - -Frequently, the functions take an instance of the `Context` type as their leading argument. This defines context about requests sent from the application such as deadlines, cancellation signals etc. More information on this can be found in the [Go documentation](https://pkg.go.dev/golang.org/x/net/context). An empty context instance can be created using `Context.Background()`. - -### Querying client for data - -A simple starting point is to fetch the chain ID from the client. This e.g. is needed when signing a transaction as is to be seen in the next section. - -```go -chainid, err := cl.ChainID(context.Background()) -if err != nil { - return err -} -``` - -Unlike `ChainID`, many functions require arguments other than context. The Go API takes in and returns high-level types which are used in Geth internals as well to simplify programming and remove the need for knowing how data needs to be formatted exactly as per the JSON-RPC API spec. For example to find out the nonce for an account at a given block the address needs to be provided as a `common.Address` type and the block number as a `*big.Int`: - -```go -addr := common.HexToAddress("0xb02A2EdA1b317FBd16760128836B0Ac59B560e9D") -nonce, err := cl.NonceAt(context.Background(), addr, big.NewInt(14000000)) -``` - -### Querying past events - -Contracts emit events during execution which can be queried from the client. The parameters for the event one is interested in have to be filled out in the `ethereum.FilterQuery` object. This includes which event topics are of interested, from which contracts and during which range of blocks. The example below queries `Transfer` events of all ERC-20 tokens for the last 10 blocks: - -```go -blockNum, err := cl.BlockNumber(context.Background()) -if err != nil { - return err -} -q := ethereum.FilterQuery{ - FromBlock: new(big.Int).Sub(blockNum, big.NewInt(10)), - ToBlock: blockNum, - Topics: [][]common.Hash{common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")}, -} -logs, err := cl.FilterLogs(context.Background(), q) -if err != nil { - return err -} -``` - -### Sending a transaction - -Sending a transaction is achieved using the `SendTransaction()` function. `SendTransaction` takes an instance of `context.Context` as its leading argument and a signed transaction as its second argument. The signed transaction must be generated in advance. Building the signed transaction is a multi-stage process that requires first generating a key pair if none exists already, retrieving some chain data and defining sender and recipient -addresses. Then these data can be collected into a transaction object and signed. The resulting signed transaction can then be passed to `SendTransaction`. - -The example below assumes the following key pair has already been generated: - -```go -// SK and ADDR are the secret key and sender address -SK = "0xaf5ead4413ff4b78bc94191a2926ae9ccbec86ce099d65aaf469e9eb1a0fa87f" -ADDR = "0x6177843db3138ae69679A54b95cf345ED759450d" -``` - -The secret key and address can be used to send a transaction. In the example below 1 ETH is sent from the address `ADDR` to an arbitrary recipient. - -```go -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/params" -) - -// sendTransaction sends a transaction with 1 ETH to a specified address. -func sendTransaction(cl *ethclient.Client) error { - var ( - sk = crypto.ToECDSAUnsafe(common.FromHex(SK)) - to = common.HexToAddress("0xb02A2EdA1b317FBd16760128836B0Ac59B560e9D") - value = new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)) - sender = common.HexToAddress(ADDR) - gasLimit = uint64(21000) - ) - // Retrieve the chainid (needed for signer) - chainid, err := cl.ChainID(context.Background()) - if err != nil { - return err - } - // Retrieve the pending nonce - nonce, err := cl.PendingNonceAt(context.Background(), sender) - if err != nil { - return err - } - // Get suggested gas price - tipCap, _ := cl.SuggestGasTipCap(context.Background()) - feeCap, _ := cl.SuggestGasPrice(context.Background()) - // Create a new transaction - tx := types.NewTx( - &types.DynamicFeeTx{ - ChainID: chainid, - Nonce: nonce, - GasTipCap: tipCap, - GasFeeCap: feeCap, - Gas: gasLimit, - To: &to, - Value: value, - Data: nil, - }) - // Sign the transaction using our keys - signedTx, _ := types.SignTx(tx, types.NewLondonSigner(chainid), sk) - // Send the transaction to our node - return cl.SendTransaction(context.Background(), signedTx) -} -``` - -### gethclient - -An instance of `gethclient` can be used in exactly the same way as `ethclient`. However, `gethclient` includes Geth-specific API methods. These additional methods are: - -```shell -CallContract() -CreatAccessList() -GCStats() -GetNodeInfo() -GetProof() -MemStats() -SetHead() -SubscribePendingTransactions() -``` - -_Note that both `ethclient` and `gethclient` have a `CallContract()` function - the difference is that the `gethclient` version includes an `overrides` argument._ - -Details relating to these endpoints can be found at [pkg.go.dev](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.10.19/ethclient/gethclient) or the Geth [Github](https://github.com/ethereum/go-ethereum/tree/master/ethclient). The code snippets in this tutorial were adapted from a more more in-depth set of examples available on [Github](https://github.com/MariusVanDerWijden/web3go). - -## Summary - -There are a wide variety of Go APIs available for dapp developers that abstract away the complexity of interacting with Ethereum using a set of composable, reusable functions provided by Geth. diff --git a/content/docs/developers/dapp-developer/tracing.md b/content/docs/developers/dapp-developer/tracing.md deleted file mode 100644 index 122ab94a97..0000000000 --- a/content/docs/developers/dapp-developer/tracing.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: EVM Tracing -description: Introduction to tracing EVM transactions using Geth ---- - -There are two different types of [transactions](https://ethereum.org/en/developers/docs/transactions) in Ethereum: simple value transfers and contract executions. A value transfer just moves Ether from one account to another. If however the recipient of a transaction is a contract account with associated [EVM](https://ethereum.org/en/developers/docs/evm) (Ethereum Virtual Machine) bytecode - beside transferring any Ether - the code will also be executed as part of the transaction. - -Having code associated with Ethereum accounts permits transactions to do arbitrarily complex data storage and enables them to act on the previously stored data by further transacting internally with outside accounts and contracts. This creates an interlinked ecosystem of contracts, where a single transaction can interact with tens or hundreds of accounts. - -The downside of contract execution is that it is very hard to say what a transaction actually did. A transaction receipt does contain a status code to check whether execution succeeded or not, but there is no way to see what data was modified, nor what external contracts where invoked. Geth resolves this by re-running transactions locally and collecting data about precisely what was executed by the EVM. This is known as "tracing" the transaction. - -## Tracing prerequisites - -In its simplest form, tracing a transaction entails requesting the Ethereum node to reexecute the desired transaction with varying degrees of data collection and have it return the aggregated summary for post processing. Reexecuting a transaction however has a few prerequisites to be met. - -In order for an Ethereum node to reexecute a transaction, all historical state accessed by the transaction must be available. This includes: - -- Balance, nonce, bytecode and storage of both the recipient as well as all internally invoked contracts. -- Block metadata referenced during execution of both the outer as well as all internally created transactions. -- Intermediate state generated by all preceding transactions contained in the same block as the one being traced. - -This means there are limits on the transactions that can be traced imposed by the synchronization and pruning configuration of a node. - -- An **archive** node retains **all historical data** back to genesis. It can therefore trace arbitrary transactions at any point in the history of the chain. Tracing a single transaction requires reexecuting all preceding transactions in the same block. - -- A **full synced** node retains the most recent 128 blocks in memory, so transactions in that range are always accessible. Full nodes also store occasional checkpoints back to genesis that can be used to rebuild the state at any point on-the-fly. This means older transactions can be traced but if there is a large distance between the requested transaction and the most recent checkpoint rebuilding the state can take a long time. Tracing a single transaction requires reexecuting all preceding transactions in the same block **and** all preceding blocks until the previous stored snapshot. - -- A **snap synced** node holds the most recent 128 blocks in memory, so transactions in that range are always accessible. However, snap-sync only starts processing from a relatively recent block (as opposed to genesis for a full node). Between the initial sync block and the 128 most recent blocks, the node stores occasional checkpoints that can be used to rebuild the state on-the-fly. This means transactions can be traced back as far as the block that was used for the initial sync. Tracing a single transaction requires reexecuting all preceding transactions in the same block, - **and** all preceding blocks until the previous stored snapshot. - -- A **light synced** node retrieving data **on demand** can in theory trace transactions for which all required historical state is readily available in the network. This is because the data required to generate the trace is requested from an les-serving full node. In practice, data - availability **cannot** be reasonably assumed. - -_There are exceptions to the above rules when running batch traces of entire blocks or chain segments. Those will be detailed later._ - -## Basic traces - -The simplest type of transaction trace that Geth can generate are raw EVM opcode traces. For every VM instruction the transaction executes, a structured log entry is emitted, containing all contextual metadata deemed useful. This includes the _program counter_, _opcode name_, _opcode cost_, _remaining gas_, _execution depth_ and any _occurred error_. The structured logs can optionally also contain the content of the _execution stack_, _execution memory_ and _contract storage_. - -The entire output of a raw EVM opcode trace is a JSON object having a few metadata fields: _consumed gas_, _failure status_, _return value_; and a list of _opcode entries_: - -```json -{ - "gas": 25523, - "failed": false, - "returnValue": "", - "structLogs": [] -} -``` - -An example log for a single opcode entry has the following format: - -```json -{ - "pc": 48, - "op": "DIV", - "gasCost": 5, - "gas": 64532, - "depth": 1, - "error": null, - "stack": [ - "00000000000000000000000000000000000000000000000000000000ffffffff", - "0000000100000000000000000000000000000000000000000000000000000000", - "2df07fbaabbe40e3244445af30759352e348ec8bebd4dd75467a9f29ec55d98d" - ], - "memory": [ - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000060" - ], - "storage": {} -} -``` - -### Generating basic traces - -To generate a raw EVM opcode trace, Geth provides a few [RPC API endpoints](/docs/rpc/ns-debug). The most commonly used is [`debug_traceTransaction`](/docs/rpc/ns-debug#debug_tracetransaction). - -In its simplest form, `traceTransaction` accepts a transaction hash as its only argument. It then traces the transaction, aggregates all the generated data and returns it as a **large** JSON object. A sample invocation from the Geth console would be: - -```js -debug.traceTransaction('0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f'); -``` - -The same call can also be invoked from outside the node too via HTTP RPC (e.g. using Curl). In this case, the HTTP endpoint must be enabled in Geth using the `--http` command and the `debug` API namespace must be exposed using `--http.api=debug`. - -``` -$ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f"]}' localhost:8545 -``` - -To follow along with this tutorial, transaction hashes can be found from a local Geth node (e.g. by attaching a [Javascript console](/docs/interface/javascript-console) and running `eth.getBlock('latest')` then passing a transaction hash from the returned block to `debug.traceTransaction()`) or from a block explorer (for [Mainnet](https://etherscan.io/) or a [testnet](https://goerli.etherscan.io/)). - -It is also possible to configure the trace by passing Boolean (true/false) values for four parameters that tweak the verbosity of the trace. By default, the _EVM memory_ and _Return data_ are not reported but the _EVM stack_ and _EVM storage_ are. To report the maximum amount of data: - -```shell -enableMemory: true -disableStack: false -disableStorage: false -enableReturnData: true -``` - -An example call, made in the Geth Javascript console, configured to report the maximum amount of data looks as follows: - -```js -debug.traceTransaction('0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f', { - enableMemory: true, - disableStack: false, - disableStorage: false, - enableReturnData: true -}); -``` - -Running the above operation on the Rinkeby network (with a node retaining enough history) will result in this [trace dump](https://gist.github.com/karalabe/c91f95ac57f5e57f8b950ec65ecc697f). - -Alternatively, disabling _EVM Stack_, _EVM Memory_, _Storage_ and _Return data_ (as demonstrated in the Curl request below) results in the following, much shorter, [trace dump](https://gist.github.com/karalabe/d74a7cb33a70f2af75e7824fc772c5b4). - -``` -$ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f", {"disableStack": true, "disableStorage": true}]}' localhost:8545 -``` - -### Limits of basic traces - -Although the raw opcode traces generated above are useful, having an individual log entry for every single opcode is too low level for most use cases, and will require developers to create additional tools to post-process the traces. Additionally, a full opcode trace can easily go into the hundreds of megabytes, making them very resource intensive to get out of the node and process externally. - -To avoid those issues, Geth supports running custom JavaScript tracers _within_ the Ethereum node, which have full access to the EVM stack, memory and contract storage. This means developers only have to gather the data they actually need, and do any processing at the source. - -## Pruning - -Geth does in-memory state-pruning by default, discarding state entries that it deems no longer necessary to maintain. This is configured via the `--gcmode` command. An error message alerting the user that the necessary state is not available is common in EVM tracing on -anything other than an archive node. - -```sh -Error: required historical state unavailable (reexec=128) - at web3.js:6365:37(47) - at send (web3,js:5099:62(35)) - at :1:23(13) -``` - -The pruning behaviour, and consequently the state availability and tracing capability of a node depends on its sync and pruning configuration. The 'oldest' block after which state is immediately available, and before which state is not immediately available, is known as the "pivot block". There are then several possible cases for a trace request on a Geth node. - -For tracing a transaction in block `B` where the pivot block is `P` can regenerate the desired state by replaying blocks from the last: - -1. a fast-sync'd node can regenerate the desired state by replaying blocks from the most recent checkpoint between `P` and `B` as long as `P` < `B`. If `P` > `B` there is no available checkpoint and the state cannot be regenerated without replying the chain from genesis. - -2. a fully sync'd node can regenerate the desired state by replaying blocks from the last available full state before `B`. A fully sync'd node re-executes all blocks from genesis, so checkpoints are available across the entire history of the chain. However, database pruning discards older data, moving `P` to a more recent position in the chain. If `P` > `B` there is no available checkpoint and the state cannot be regenerated without replaying the chain from genesis. - -3. A fully-sync'd node without pruning (i.e. an archive node configured with `--gcmode=archive`) does not need to replay anything, it can immediately load up any state and serve the request for any `B`. - -The time taken to regenerate a specific state increases with the distance between `P` and `B`. If the distance between `P` and `B` is large, the regeneration time can be substantial. - -## Summary - -This page covered the concept of EVM tracing and how to generate traces with the default opcode-based tracers using RPC. More advanced usage is possible, including using other built-in tracers as well as writing [custom tracing](/docs/dapp/custom-tracer) code in Javascript and Go. The API as well as the JS tracing hooks are defined in [the reference](/docs/rpc/ns-debug#debug_traceTransaction). - -[evm]: diff --git a/content/docs/developers/geth-developer/Private-Network.md b/content/docs/developers/geth-developer/Private-Network.md deleted file mode 100644 index 526ce46453..0000000000 --- a/content/docs/developers/geth-developer/Private-Network.md +++ /dev/null @@ -1,461 +0,0 @@ ---- -title: Private Networks -description: Tutorial on setting up private Ethereum networks ---- - -This guide explains how to set up a private network of multiple Geth nodes. An Ethereum network is private if the nodes are not connected to the main network. In this context private only means reserved or isolated, rather than protected or secure. A fully controlled, private Ethereum network is useful as a backend for core developers working on issues relating to networking/blockchain syncing etc. Private networks are also useful for Dapp developers testing multi-block and multi-user scenarios. - -## Prerequisites - -To follow the tutorial on this page it is necessary to have a working Geth installation (instructions [here](content/docs/getting_started/Installing-Geth.md)). It is also helpful to understand Geth fundamentals (see [Getting Started](/content/docs/getting_started/getting_started.md)). - -## Private Networks - -A private network is composed of multiple Ethereum nodes that can only connect to each other. In order to run multiple nodes locally, each one requires a separate data directory (`--datadir`). The nodes must also know about each other and be able to exchange information, share an initial state and a common consensus algorithm. The remainder of this page will explain how to configure Geth so that these basic requirements are met, enabling a private network to be started. - -### Choosing A Network ID - -Ethereum Mainnet has Network ID = 1. There are also many other networks that Geth can connect to by providing alternative Chain IDs, some are testnets and others are alternative networks built from forks of the Geth source code. Providing a network ID that is not already being used by an existing network or testnet means the nodes using that network ID can only connect to each other, creating a private network. A list of current network IDs is available at [Chainlist.org](https://chainlist.org/). The network ID is controlled using the `networkid` flag, e.g. - -```shell -geth --networkid 12345 -``` - -### Choosing A Consensus Algorithm - -While the main network uses proof-of-work (PoW) to secure the blockchain, Geth also supports the the 'Clique' proof-of-authority (PoA) consensus algorithm as an alternative for private networks. Clique is strongly recommended for private testnets because PoA is far less resource-intensive than PoW. Clique is currently used as the consensus algorithm in public testnets such as [Rinkeby](https://www.rinkeby.io) and [Görli](https://goerli.net). The key differences between the consensus algorithms available in Geth are: - -#### Ethash - -Geth's PoW algorithm, [Ethhash](https://ethereum.org/en/developers/docs/consensus-mechanisms/pow/mining-algorithms/ethash), is a system that allows open participation by anyone willing to dedicate resources to mining. While this is a critical property for a public network, the overall security of the blockchain strictly depends on the total amount of resources used to secure it. As such, PoW is a poor choice for private networks with few miners. The Ethash mining 'difficulty' is adjusted automatically so that new blocks are created approximately 12 seconds apart. As more mining resources are deployed on the network, creating a new block becomes harder so that the average block time matches the target block time. - -#### Clique - -Clique consensus is a PoA system where new blocks can be created by authorized 'signers' only. The clique consenus protocol is specified in [EIP-225](https://eips.ethereum.org/EIPS/eip-225). The initial set of authorized signers is configured in the genesis block. Signers can be authorized and de-authorized using a voting mechanism, thus allowing the set of signers to change while the blockchain operates. Clique can be configured to target any block time (within reasonable limits) since it isn't tied to the difficulty adjustment. - -### Creating The Genesis Block - -Every blockchain starts with a genesis block. When Geth is run with default settings for the first time, it commits the Mainnet genesis to the database. For a private network, it is generally preferable to use a different genesis block. The genesis block is configured using a _genesis.json_ file whose path must be provided to Geth on start-up. When creating a genesis block, a few initial parameters for the private blockchain must be defined: - -- Ethereum platform features enabled at launch (`config`). Enabling and disabling features once the blockchain is running requires scheduling a [hard fork](https://ethereum.org/en/glossary/#hard-fork). -- Initial block gas limit (`gasLimit`). This impacts how much EVM computation can happen within a single block. Mirroring the main Ethereum network is generally a [good choice](https://etherscan.io/chart/gaslimit). The block gas limit can be adjusted after launch using the `--miner.gastarget` command-line flag. - -- Initial allocation of ether (`alloc`). This determines how much ether is available to the addresses listed in the genesis block. Additional ether can be created through mining as the chain progresses. - -#### Clique Example - -Below is an example of a `genesis.json` file for a PoA network. The `config` section ensures that all known protocol changes are available and configures the 'clique' engine to be used for consensus. Note that the initial signer set must be configured through the `extradata` field. This field is required for Clique to work. - -The signer account keys can be generated using the [geth account](/content/docs/fundamentals/account-management.md) command (this command can be run multiple times to create more than one signer key). - -```shell -geth account new --datadir data -``` - -The Ethereum address printed by this command should be recorded. To encode the signer addresses in `extradata`, concatenate 32 zero bytes, all signer addresses and 65 further zero bytes. The result of this concatenation is then used as the value accompanying the `extradata` key in `genesis.json`. In the example below, `extradata` contains a single initial signer address, `0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82`. - -The `period` configuration option sets the target block time of the chain. - -```json -{ - "config": { - "chainId": 12345, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "clique": { - "period": 5, - "epoch": 30000 - } - }, - "difficulty": "1", - "gasLimit": "8000000", - "extradata": "0x00000000000000000000000000000000000000000000000000000000000000007df9a875a174b3bc565e6424a0050ebc1b2d1d820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "alloc": { - "7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000" }, - "f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000" } - } -} -``` - -#### Ethash Example - -Since Ethash is the default consensus algorithm, no additional parameters need to be configured in order to use it. The initial mining difficulty is influenced using the `difficulty` parameter, but note that the difficulty adjustment algorithm will quickly adapt to the amount of mining resources deployed on the chain. - -```json -{ - "config": { - "chainId": 12345, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "ethash": {} - }, - "difficulty": "1", - "gasLimit": "8000000", - "alloc": { - "7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000" }, - "f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000" } - } -} -``` - -### Initializing the Geth Database - -To create a blockchain node that uses this genesis block, first use `geth init` to import and sets the canonical genesis block for the new chain. This requires the path to `genesis.json` to be passed as an argument. - -```shell -geth init --datadir data genesis.json -``` - -When Geth is started using `--datadir data` the genesis block defined in `genesis.json` will be used. For example: - -```shell -geth --datadir data --networkid 12345 -``` - -### Scheduling Hard Forks - -As Ethereum protocol development progresses, new features become available. To enable these features on an existing private network, a hard fork must be scheduled. To do this, a future block number must be chosen which determines precisely when the hard fork will activate. Continuing the `genesis.json` example above and assuming the current block number is 35421, a hard fork might be scheduled for block 40000. This hard fork might upgrade the network to conform to the 'London' specs. First, all the Geth instances on the private network must be recent enough to support the specific hard fork. If so, `genesis.json` can be updated so that the `londonBlock` key gets the value 40000. The Geth instances are then shut down and `geth init` is run to update their configuration. When the nodes are restarted they will pick up where they left off and run normally until block 40000, at which point they will automatically upgrade. - -The modification to `genesis.json` is as follows: - -```json -{ - "config": { - "londonBlock": 40000 - } -} -``` - -The upgrade command is: - -```shell -geth init --datadir data genesis.json -``` - -### Setting Up Networking - -With the node configured and initialized, the next step is to set up a peer-to-peer network. This requires a bootstrap node. The bootstrap node is a normal node that is designated to be the entry point that other nodes use to join the network. Any node can be chosen to be the bootstrap node. - -To configure a bootstrap node, the IP address of the machine the bootstrap node will run on must be known. The bootsrap node needs to know its own IP address so that it can broadcast it to other nodes. On a local machine this can be found using tools such as `ifconfig` and on cloud instances such as Amazon EC2 the IP address of the virtual machine can be found in the management console. Any firewalls must allow UDP and TCP traffic on port 30303. - -The bootstrap node IP is set using the `--nat` flag (the command below contains an example address - replace it with the correct one). - -```shell -geth --datadir data --networkid 15 --nat extip:172.16.254.4 -``` - -The 'node record' of the bootnode can be extracted using the JS console: - -```shell -geth attach data/geth.ipc --exec admin.nodeInfo.enr -``` - -This command should print a base64 string such as the following example. Other nodes will use the information contained in the bootstrap node record to connect to the peer-to-peer network. - -```text -"enr:-Je4QEiMeOxy_h0aweL2DtZmxnUMy-XPQcZllrMt_2V1lzynOwSx7GnjCf1k8BAsZD5dvHOBLuldzLYxpoD5UcqISiwDg2V0aMfGhGlQhqmAgmlkgnY0gmlwhKwQ_gSJc2VjcDI1NmsxoQKX_WLWgDKONsGvxtp9OeSIv2fRoGwu5vMtxfNGdut4cIN0Y3CCdl-DdWRwgnZf" -``` - -If the nodes are intended to connect across the Internet, the bootnode and all other nodes must have public IP addresses assigned, and both TCP and UDP traffic can pass their firewalls. If Internet connectivity is not required or all member nodes connect using well-known IPs, Geth should be set up to restrict peer-to-peer connectivity to an IP subnet. Doing so will further isolate the network and prevents cross-connecting with other blockchain networks in case the nodes are reachable from the Internet. Use the -`--netrestrict` flag to configure a whitelist of IP networks: - -```shell -geth --netrestrict 172.16.254.0/24 -``` - -With the above setting, Geth will only allow connections from the 172.16.254.0/24 subnet, and will not attempt to connect to other nodes outside of the set IP range. - -### Running Member Nodes - -Before running a member node, it must be initialized with the same genesis file as used for the bootstrap node. With the bootnode operational and externally reachable (`telnet ` will confirm that it is indeed reachable), more Geth nodes can be started and connected to them via the bootstrap node using the `--bootnodes` flag. The process is to start Geth on the same machine as the bootnode, with a separate data directory and listening port and the bootnode node record provided as an argument: - -For example, using data directory (example: `data2`) and listening port (example: `30305`): - -```shell -geth --datadir data2 --networkid 12345 --port 30305 --bootnodes -``` - -With the member node running, it is possible to check that it is connected to the bootstrap node or any other node in the network by attaching a console and running `admin.peers`. It may take up to a few seconds for the nodes to get connected. - -```shell -geth attach data2/geth.ipc --exec admin.peers -``` - -### Running A Signer (Clique) - -To set up Geth for signing blocks in Clique, a signer account must be available. The account must already be available as a keyfile in the keystore. To use it for signing blocks, it must be unlocked. The following command, for address `0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82` will prompt for the account password, then start signing blocks: - -```shell -geth --unlock 0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82 --mine -``` - -Mining can be further configured by changing the default gas limit blocks converge to (with `--miner.gastarget`) and the price transactions are accepted at (with `--miner.gasprice`). - -### Running A Miner (Ethash) - -For PoW in a simple private network, a single CPU miner instance is enough to create a stable stream of blocks at regular intervals. To start a Geth instance for mining, it can be run with all the usual flags plus the following to configure mining: - -```shell -geth --mine --miner.threads=1 --miner.etherbase=0xf41c74c9ae680c1aa78f42e5647a62f353b7bdde -``` - -This will start mining bocks and transactions on a single CPU thread, crediting all block rewards to the account specified by `--miner.etherbase`. - -## End-to-end example {#end-to-end-example} - -This section will run through the commands for setting up a simple private network of two nodes. Both nodes will run on the local machine using the same genesis block and network ID. The data directories for each node will be named `node1` and `node2`. - -```shell -`mkdir node1 node2` -``` - -Each node will have an associated account that will receive some ether at launch. The following command creates an account for Node 1: - -```shell -geth --datadir node1 account new -``` - -This command returns a request for a password. Once a password has been provided the following information is returned to the terminal: - -```terminal -Your new account is locked with a password. Please give a password. Do not foget this password. -Password: -Repeat password: - -Your new key was generated - -Public address of the key: 0xC1B2c0dFD381e6aC08f34816172d6343Decbb12b -Path of the secret key file: node1/keystore/UTC--2022-05-13T14-25-49.229126160Z--c1b2c0dfd381e6ac08f34816172d6343decbb12b - -- You can share your public address with anyone. Others need it to interact with you. -- You must NEVER share the secret key with anyone! The key controls access to your funds! -- You must BACKUP your key file! Without the key, it's impossible to access account funds! -- You must remember your password! Without the password, it's impossible to decrypt the key! -``` - -The keyfile and account password should be backed up securely. These steps can then be repeated for Node 2. These commands create keyfiles that are stored in the `keystore` directory in `node1` and `node2` data directories. In order to unlock the accounts later the passwords for each account should be saved to a text file in each node's data directory. - -In each data directory save a copy of the following `genesis.json` to the top level project directory. The account addresses in the `alloc` field should be replaced with those created for each node in the previous step (without the leading `0x`). - -```json -{ - "config": { - "chainId": 12345, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "arrowGlacierBlock": 0, - "grayGlacierBlock": 0, - "clique": { - "period": 5, - "epoch": 30000 - } - }, - "difficulty": "1", - "gasLimit": "800000000", - "extradata": "0x00000000000000000000000000000000000000000000000000000000000000007df9a875a174b3bc565e6424a0050ebc1b2d1d820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "alloc": { - "C1B2c0dFD381e6aC08f34816172d6343Decbb12b": { "balance": "500000" }, - "c94d95a5106270775351eecfe43f97e8e75e59e8": { "balance": "500000" } - } -} -``` - -The nodes can now be set up using `geth init` as follows: - -```shell -geth init --datadir node1 genesis.json -``` - -This should be repeated for both nodes. The following will be returned to the terminal: - -```terminal -INFO [05-13|15:41:47.520] Maximum peer count ETH=50 LES=0 total=50 -INFO [05-13|15:41:47.520] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory" -INFO [05-13|15:41:47.520] Set global gas cap cap=50,000,000 -INFO [05-13|15:41:47.520] Allocated cache and file handles database=/home/go-ethereum/node2/geth/chaindata cache=16.00MiB handles=16 -INFO [05-13|15:41:47.542] Writing custom genesis block -INFO [05-13|15:41:47.542] Persisted trie from memory database nodes=3 size=397.00B time="41.246µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B -INFO [05-13|15:41:47.543] Successfully wrote genesis state database=chaindata hash=c9a158..d415a0 -INFO [05-13|15:41:47.543] Allocated cache and file handles database=/home/go-ethereum/node2/geth/chaindata cache=16.00MiB handles=16 -INFO [05-13|15:41:47.556] Writing custom genesis block -INFO [05-13|15:41:47.557] Persisted trie from memory database nodes=3 size=397.00B time="81.801µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B -INFO [05-13|15:41:47.558] Successfully wrote genesis state database=chaindata hash=c9a158..d415a0 -``` - -The next step is to configure a bootnode. This can be any node, but for this tutorial the developer tool `bootnode` will be used to quickly and easily configure a dedicated bootnode. First the bootnode requires a key, which can be created with the following command, which will save a key to `boot.key`: - -```shell -bootnode -genkey boot.key -``` - -This key can then be used to generate a bootnode as follows: - -``` -bootnode -nodekey boot.key -addr :30305 -``` - -The choice of port passed to `-addr` is arbitrary, but public Ethereum networks use 30303, so this is best avoided. The `bootnode` command returns the following logs to the terminal, confirming that it is running: - -```terminal -enode://f7aba85ba369923bffd3438b4c8fde6b1f02b1c23ea0aac825ed7eac38e6230e5cadcf868e73b0e28710f4c9f685ca71a86a4911461637ae9ab2bd852939b77f@127.0.0.1:0?discport=30305 -Note: you're using cmd/bootnode, a developer tool. -We recommend using a regular node as bootstrap node for production deployments. -INFO [05-13|15:50:03.645] New local node record seq=1,652,453,403,645 id=a2d37f4a7d515b3a ip=nil udp=0 tcp=0 -``` - -The two nodes can now be started. Open separate terminals for each node, leaving the bootnode running in the original terminal. In each terminal, run the following command (replacing `node1` with `node2` where appropriate, and giving each node a different port ID. The account address and password file for node 1 must also be provided: - -```shell -./geth --datadir node1 --port 30306 --bootnodes enode://f7aba85ba369923bffd3438b4c8fde6b1f02b1c23ea0aac825ed7eac38e6230e5cadcf868e73b0e28710f4c9f685ca71a86a4911461637ae9ab2bd852939b77f@127.0.0.1:0?discport=30305 --networkid 123454321 --unlock 0xC1B2c0dFD381e6aC08f34816172d6343Decbb12b --password node1/password.txt -``` - -This will start the node using the bootnode as an entry point. Repeat the same command with the information appropriate to node 2. In each terminal, the following logs indicate success: - -```terminal -INFO [05-13|16:17:40.061] Maximum peer count ETH=50 LES=0 total=50 -INFO [05-13|16:17:40.061] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory" -INFO [05-13|16:17:40.061] Set global gas cap cap=50,000,000 -INFO [05-13|16:17:40.061] Allocated trie memory caches clean=154.00MiB dirty=256.00MiB -INFO [05-13|16:17:40.061] Allocated cache and file handles database=/home/go-ethereum/node1/geth/chaindata cache=512.00MiB handles=524,288 -INFO [05-13|16:17:40.094] Opened ancient database database=/home/go-ethereum/node1/geth/chaindata/ancient readonly=false -INFO [05-13|16:17:40.095] Initialised chain configuration config="{ChainID: 123454321 Homestead: 0 DAO: nil DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: nil, Muir Glacier: nil, Berlin: nil, London: nil, Arrow Glacier: nil, MergeFork: nil, Terminal TD: nil, Engine: clique}" -INFO [05-13|16:17:40.096] Initialising Ethereum protocol network=123,454,321 dbversion=8 -INFO [05-13|16:17:40.098] Loaded most recent local header number=0 hash=c9a158..d415a0 td=1 age=53y1mo2w -INFO [05-13|16:17:40.098] Loaded most recent local full block number=0 hash=c9a158..d415a0 td=1 age=53y1mo2w -INFO [05-13|16:17:40.098] Loaded most recent local fast block number=0 hash=c9a158..d415a0 td=1 age=53y1mo2w -INFO [05-13|16:17:40.099] Loaded local transaction journal transactions=0 dropped=0 -INFO [05-13|16:17:40.100] Regenerated local transaction journal transactions=0 accounts=0 -INFO [05-13|16:17:40.100] Gasprice oracle is ignoring threshold set threshold=2 -WARN [05-13|16:17:40.100] Unclean shutdown detected booted=2022-05-13T16:16:46+0100 age=54s -INFO [05-13|16:17:40.100] Starting peer-to-peer node instance=Geth/v1.10.18-unstable-8d84a701-20220503/linux-amd64/go1.18.1 -INFO [05-13|16:17:40.130] New local node record seq=1,652,454,949,228 id=f1364e6d060c4625 ip=127.0.0.1 udp=30306 tcp=30306 -INFO [05-13|16:17:40.130] Started P2P networking self=enode://87606cd0b27c9c47ca33541d4b68cf553ae6765e22800f0df340e9788912b1e3d2759b3d1933b6f739c720701a56ce26f672823084420746d04c25fc7b8c6824@127.0.0.1:30306 -INFO [05-13|16:17:40.133] IPC endpoint opened url=/home/go-ethereum/node1/geth.ipc -INFO [05-13|16:17:40.785] Unlocked account address=0xC1B2c0dFD381e6aC08f34816172d6343Decbb12b -INFO [05-13|16:17:42.636] New local node record seq=1,652,454,949,229 id=f1364e6d060c4625 ip=82.11.59.221 udp=30306 tcp=30306 -INFO [05-13|16:17:43.309] Mapped network port proto=tcp extport=30306 intport=30306 interface="UPNP IGDv1-IP1" -INFO [05-13|16:17:43.822] Mapped network port proto=udp extport=30306 intport=30306 interface="UPNP IGDv1-IP1" -[05-13|16:17:50.150] Looking for peers peercount=0 tried=0 static=0 -INFO [05-13|16:18:00.164] Looking for peers peercount=0 tried=0 static=0 -``` - -In the first terminal that is currently running the logs resembling the following will be displayed, showing the discovery process in action: - -```terminal -INFO [05-13|15:50:03.645] New local node record seq=1,652,453,403,645 id=a2d37f4a7d515b3a ip=nil udp=0 tcp=0 -TRACE[05-13|16:15:49.228] PING/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:49.229] PONG/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:49.229] PING/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:49.230] PONG/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:49.730] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:49.731] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.231] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.231] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.561] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.561] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.731] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:50.731] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:51.231] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:51.232] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:52.591] FINDNODE/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:52.591] NEIGHBORS/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -TRACE[05-13|16:15:57.767] PING/v4 id=f1364e6d060c4625 addr=127.0.0.1:30306 err=nil -``` - -It is now possible to attach a Javascript console to either node to query the network properties: - -```shell -geth attach node1/geth.ipc -``` - -Once the Javascript console is running, check that the node is connected to one other peer (node 2): - -```shell -net.peerCount -``` - -The details of this peer can also be queried and used to check that the peer really is Node 2: - -``` -admin.peers -``` - -This should return the following: - -```terminal -[{ - caps: ["eth/66", "snap/1"], - enode: "enode://6a4576fb12004aa13949dbf25de978102483a6521e6d5d87c5b7ccb1944bbf8995dc730303ae891732410b1dd2e684277e9292fc0a17372a789bb4e87bdf366b@127.0.0.1:30307", - id: "d300c59ba301abcb5f4a3866aab6f833857c3ddf2f0febb583410b1dc466f175", - name: "Geth/v1.10.18-unstable-8d84a701-20220503/linux-amd64/go1.18.1", - network: { - inbound: false, - localAddress: "127.0.0.1:56620", - remoteAddress: "127.0.0.1:30307", - static: false, - trusted: false - }, - protocols: { - eth: { - difficulty: 1, - head: "0xc9a158a687eff8a46128bd5b9aaf6b2f04f10f0683acbd7f031514db9ad415a0", - version: 66 - }, - snap: { - version: 1 - } - } -}] -``` - -The account associated with Node 1 was supposed to be funded with some ether at the chain genesis. This can be checked easily using `eth.getBalance()`: - -```shell -eth.getBalance(eth.accounts[0]) -``` - -This account can then be unlocked and some ether sent to Node 2, using the following commands: - -```javascript -// unlock account -personal.unlock(eth.accounts[0]); - -// send some Wei -eth.sendTransaction({ - to: '0xc94d95a5106270775351eecfe43f97e8e75e59e8', - from: eth.accounts[0], - value: 25000 -}); - -//check the transaction was successful by querying Node 2's account balance -eth.getBalance('0xc94d95a5106270775351eecfe43f97e8e75e59e8'); -``` - -The same steps can then be repeated to attach a console to Node 2. - -## Summary - -This page explored the various options for configuring a local private network. A step by step guide showed how to set up and launch a private network, unlock the associated accounts, attach a console to check the network status and make some basic interactions. diff --git a/content/docs/developers/geth-developer/code-review-guidelines.md b/content/docs/developers/geth-developer/code-review-guidelines.md deleted file mode 100644 index dafd3eae8e..0000000000 --- a/content/docs/developers/geth-developer/code-review-guidelines.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Code Review Guidelines -description: Explanation of how code PRs are reviewed ---- - -The only way to get code into Geth is to submit a pull request (PR). Those pull requests need to be reviewed by someone. This document is a guide that explains our expectations around PRs for both authors and reviewers. - -## Terminology - -- The **author** of a pull request is the entity who wrote the diff and submitted it to GitHub. - -- The **team** consists of people with commit rights on the go-ethereum repository. -- The **reviewer** is the person assigned to review the diff. The reviewer must be a team member. -- The **code owner** is the person responsible for the subsystem being modified by the PR. - -## The Process - -The first decision to make for any PR is whether it's worth including at all. This decision lies primarily with the code owner, but may be negotiated with team members. - -To make the decision we must understand what the PR is about. If there isn't enough description content or the diff is too large, request an explanation. Anyone can do this part. - -We expect that reviewers check the style and functionality of the PR, providing comments to the author using the GitHub review system. Reviewers should follow up with the PR until it is in good shape, then **approve** the PR. Approved PRs can be merged by any code owner. - -When communicating with authors, be polite and respectful. - -### Code Style - -We expect `gofmt`ed code. For contributions of significant size, we expect authors to understand and use the guidelines in [Effective Go](https://golang.org/doc/effective_go.html). Authors should avoid common mistakes explained in the [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) page. - -### Functional Checks - -For PRs that fix an issue, reviewers should try reproduce the issue and verify that the pull request actually fixes it. Authors can help with this by including a unit test that fails without (and passes with) the change. - -For PRs adding new features, reviewers should attempt to use the feature and comment on how it feels to use it. Example: if a PR adds a new command line flag, use the program with the flag and comment on whether the flag feels useful. - -We expect appropriate unit test coverage. Reviewers should verify that new code is covered by unit tests. - -### CI - -Code submitted must pass all unit tests and static analysis ("lint") checks. We use Travis CI to test code on Linux, macOS and AppVeyor to test code on Microsoft Windows. - -For failing CI builds, the issue may not be related to the PR itself. Such failures are usually related to flakey tests. These failures can be ignored (authors don't need to fix unrelated issues), but please file a GH issue so the test gets fixed eventually. - -### Commit Messages - -Commit messages on the master branch should follow the rule below. PR authors are not required to use any particular style because the message can be modified at merge time. Enforcing commit message style is the responsibility of the person merging the PR. - -The commit message style we use is similar to the style used by the Go project: - -The first line of the change description is conventionally a one-line summary of the change, prefixed by the primary affected Go package. It should complete the sentence "This change modifies go-ethereum to **\_**." The rest of the description elaborates and should provide context for the change and explain what it does. - -Template: - -```text -package/path: change XYZ - -Longer explanation of the change in the commit. You can use multiple sentences here. It's usually best to include content from the PR description in the final commit message. - -issue notices, e.g. "Fixes #42353". -``` - -### Special Situations And How To Deal With Them - -Reviewers may find themselves in one of the sitations below. Here's how to deal with them: - -- The author doesn't follow up: ping them after a while (i.e. after a few days). If there is no further response, close the PR or complete the work yourself. - -- Author insists on including refactoring changes alongside bug fix: We can tolerate small refactorings alongside any change. If you feel lost in the diff, ask the author to submit the refactoring as an independent PR, or at least as an independent commit in the same PR. - -- Author keeps rejecting feedback: reviewers have authority to reject any change for technical reasons. If you're unsure, ask the team for a second opinion. The PR can be closed if no consensus can be reached. diff --git a/content/docs/developers/geth-developer/dev-mode.md b/content/docs/developers/geth-developer/dev-mode.md deleted file mode 100644 index 805ea8c0dc..0000000000 --- a/content/docs/developers/geth-developer/dev-mode.md +++ /dev/null @@ -1,300 +0,0 @@ ---- -title: Developer mode -description: Instructions for setting up Geth in developer mode ---- - -It is often convenient for developers to work in an environment where changes to client or application software can be deployed and tested rapidly and without putting real-world users or assets at risk. For this purpose, Geth has a `--dev` flag that spins up Geth in "developer mode". This creates a single-node Ethereum test network with no connections to any external peers. It exists solely on the local machine. Starting Geth in developer mode does the following: - -- Initializes the data directory with a testing genesis block -- Sets max peers to 0 (meaning Geth does not search for peers) -- Turns off discovery by other nodes (meaning the node is invisible to other nodes) -- Sets the gas price to 0 (no cost to send transactions) -- Uses the Clique proof-of-authority consensus engine which allows blocks to be mined as-needed without excessive CPU and memory consumption -- Uses on-demand block generation, producing blocks when transactions are waiting to be mined - -This configuration enables developers to experiment with Geth's source code or develop new applications without having to sync to a pre-existing public network. Blocks are only mined when there are pending transactions. Developers can break things on this network without affecting other users. This page will demonstrate how to spin up a local Geth testnet and a simple smart contract will be deployed to it using the Remix online integrated development environment (IDE). - -## Prerequisites - -It is assumed that the user has a working Geth installation (see [installation guide](/docs/install-and-build/installing-geth)). -It would also be helpful to have basic knowledge of Geth and the Geth console. See [Getting Started](/docs/getting-started). -Some basic knowledge of [Solidity](https://docs.soliditylang.org/) and [smart contract deployment](https://ethereum.org/en/developers/tutorials/deploying-your-first-smart-contract/) would be useful. - -## Start Geth in Dev Mode - -Starting Geth in developer mode is as simple as providing the `--dev` flag. It is also possible to create a realistic block creation frequency by setting `--dev.period 13` instead of creating blocks only when transactions are pending. There are also additional configuration options required to follow this tutorial. - -Remix will be used to deploy a smart contract to the node which requires information to be exchanged externally to Geth's own domain. To permit this, enable `http` and the `net` namespace must be enabled and the Remix URL must be provided to `--http.corsdomain`. For this tutorial some other namespaces will also be enabled. The full command is as follows: - -```shell -geth --dev --http --http.api eth,web3,personal,net --http.corsdomain "http://remix.ethereum.org" -``` - -The terminal will display the following logs, confirming Geth has started successfully in developer mode: - -```terminal -INFO [05-09|10:49:02.951] Starting Geth in ephemeral dev mode... -INFO [05-09|10:49:02.952] Maximum peer count ETH=50 LES=0 total=50 -INFO [05-09|10:49:02.952] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory" -INFO [05-09|10:49:02.953] Set global gas cap cap=50,000,000 -INFO [05-09|10:49:03.133] Using developer account address=0x7Aa16266Ba3d309e3cb278B452b1A6307E52Fb62 -INFO [05-09|10:49:03.196] Allocated trie memory caches clean=154.00MiB dirty=256.00MiB -INFO [05-09|10:49:03.285] Writing custom genesis block -INFO [05-09|10:49:03.286] Persisted trie from memory database nodes=13 size=1.90KiB time="180.524µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B -INFO [05-09|10:49:03.287] Initialised chain configuration config="{ ChainID: 1337 Homestead: 0 DAO: nil DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: 0, Berlin: 0, London: 0, Arrow Glacier: nil, MergeFork: nil, Terminal TD: nil, Engine: clique}" -INFO [05-09|10:49:03.288] Initialising Ethereum protocol network=1337 dbversion= nil -INFO [05-09|10:49:03.289] Loaded most recent local header number=0 hash=c9c3de..579bb8 td=1 age=53y1mo1w -INFO [05-09|10:49:03.289] Loaded most recent local full block number=0 hash=c9c3de..579bb8 td=1 age=53y1mo1w -INFO [05-09|10:49:03.289] Loaded most recent local fast block number=0 hash=c9c3de..579bb8 td=1 age=53y1mo1w -WARN [05-09|10:49:03.289] Failed to load snapshot, regenerating err="missing or corrupted snapshot" -INFO [05-09|10:49:03.289] Rebuilding state snapshot -INFO [05-09|10:49:03.290] Resuming state snapshot generation root=ceb850..0662cb accounts=0 slots=0 storage=0.00B elapsed="778.089µs" -INFO [05-09|10:49:03.290] Regenerated local transaction journal transactions=0 accounts=0 -INFO [05-09|10:49:03.292] Gasprice oracle is ignoring threshold set threshold=2 -INFO [05-09|10:49:03.292] Generated state snapshot accounts=10 slots=0 storage=412.00B elapsed=2.418ms -WARN [05-09|10:49:03.292] Error reading unclean shutdown markers error="leveldb: not found" -INFO [05-09|10:49:03.292] Starting peer-to-peer node instance=Geth/v1.10.18-unstable-8d84a701-20220503/linux-amd64/go1.18.1 -WARN [05-09|10:49:03.292] P2P server will be useless, neither dialing nor listening -INFO [05-09|10:49:03.292] Stored checkpoint snapshot to disk number=0 hash=c9c3de..579bb8 -INFO [05-09|10:49:03.312] New local node record seq=1,652,089,743,311 id=bfedca74bea20733 ip=127.0.0.1 udp=0 tcp=0 -INFO [05-09|10:49:03.313] Started P2P networking self=enode://0544de6446dd5831daa5a391de8d0375d93ac602a95d6a182d499de31f22f75b6645c3f562932cac8328d51321b676c683471e2cf7b3c338bb6930faf6ead389@127.0.0.1:0 -INFO [05-09|10:49:03.314] IPC endpoint opened url=/tmp/geth.ipc -INFO [05-09|10:49:03.315] HTTP server started endpoint=127.0.0.1:8545 auth=false prefix= cors=http:remix.ethereum.org vhosts=localhost -INFO [05-09|10:49:03.315] Transaction pool price threshold updated price=0 -INFO [05-09|10:49:03.315] Updated mining threads threads=0 -INFO [05-09|10:49:03.315] Transaction pool price threshold updated price=1 -INFO [05-09|10:49:03.315] Etherbase automatically configured address=0x7Aa16266Ba3d309e3cb278B452b1A6307E52Fb62 -INFO [05-09|10:49:03.316] Commit new sealing work number=1 sealhash=2372a2..7fb8e7 uncles=0 txs=0 gas=0 fees=0 elapsed="202.366µs" -WARN [05-09|10:49:03.316] Block sealing failed err="sealing paused while waiting for transactions" -INFO [05-09|10:49:03.316] Commit new sealing work number=1 sealhash=2372a2..7fb8e7 uncles=0 txs=0 gas=0 fees=0 elapsed="540.054µs" -``` - -This terminal must be left running throughout the entire tutorial. In a second terminal, attach a Javascript console. By default the `ipc` file is saved in the `datadir`: - -```shell -geth attach /geth.ipc -``` - -The Javascript terminal will open with the following welcome message: - -```terminal -Welcome to the Geth Javascript console! - -instance: Geth/v1.10.18-unstable-8d84a701-20220503/linux-amd64/go.1.18.1 -coinbase: 0x540dbaeb2390f2eb005f7a6dbf3436a0959197a9 -at block: 0 (Thu Jan 01 1970 01:00:00 GMT+0100 (BST)) - modules: eth:1.0 personal:1.0 rpc:1.0 web3:1.0 - -To exit, press ctrl-d or type exit -> -``` - -For simplicity this tutorial uses Geth's built-in account management. First, the existing accounts can be displayed using `eth.accounts`: - -```shell -eth.accounts -``` - -An array containing a single address will be displayed in the terminal, despite no accounts having yet been explicitly created. This is the "coinbase" account. The coinbase address is the recipient of the total amount of ether created at the local network genesis. Querying the ether balance of the coinbase account will return a very large number. The coinbase account can be invoked as `eth.accounts[0]` or as `eth.coinbase`: - -```terminal -> eth.coinbase==eth.accounts[0] -true -``` - -The following command can be used to query the balance. The return value is in units of Wei, which is divided by 118 to give units of ether. This can be done explicitly or by calling the `web3.FromWei()` function: - -```shell -eth.getBalance(eth.coinbase)/1e18 - -// or - -web3.fromWei(eth.getBalance(eth.coinbase)) -``` - -Using `web3.fromWei()` is less error prone because the correct multiplier is built in. These commands both return the following: - -```terminal -1.157920892373162e+59 -``` - -A new account can be created and some of the ether from the coinbase transferred across to it. A new account is generated using the `newAccount` function in the `personal` namespace: - -```shell -personal.newAccount() -``` - -The terminal will display a request for a password, twice. Once provided, a new account will be created and its address printed to the terminal. The account creation is also logged in the Geth terminal, including the location of the keyfile in the keystore. It is a good idea to back up the password somewhere at this point. If this were an account on a live network, intended to own assets of real-world value, it would be critical to back up the account password and the keystore in a secure manner. - -To reconfirm the account creation, running `eth.accounts` in the Javascript console should display an array containing two account addresses, one being the coinbase and the other being the newly generated address. The following command transfers 50 ETH from the coinbase to the new account: - -```shell -eth.sendTransaction({from: eth.coinbase, to: eth.accounts[1], value: web3.toWei(50, "ether")}) -``` - -A transaction hash will be returned to the console. This transaction hash will also be displayed in the logs in the Geth console, followed by logs confirming that a new block was mined (remember in the local development network blocks are mined when transactions are pending). The transaction details can be displayed in the Javascript console by passing the transaction hash to `eth.getTransaction()`: - -```shell -eth.getTransaction("0x62044d2cab405388891ee6d53747817f34c0f00341cde548c0ce9834e9718f27") -``` - -The transaction details are displayed as follows: - -```terminal -{ - accessList: [], - blockHash: "0xdef68762539ebfb247e31d749acc26ab5df3163aabf9d450b6001c200d17da8a", - blockNumber: 1, - chainId: "0x539", - from: "0x540dbaeb2390f2eb005f7a6dbf3436a0959197a9", - gas: 21000, - gasPrice: 875000001, - hash: "0x2326887390dc04483d435a6303dc05bd2648086eab15f24d7dcdf8c26e8af4b8", - input: "0x", - maxFeePerGas: 2000000001, - maxPriorityFeePerGas: 1, - nonce: 0, - r: "0x3f7b54f095b837ec13480eab5ac7de082465fc79f43b813cca051394dd028d5d", - s: "0x167ef271ae8175239dccdd970db85e06a044d5039252d6232d0954d803bb4e3e", - to: "0x43e3a14fb8c68caa7eea95a02693759de4513950", - transactionIndex: 0, - type: "0x2", - v: "0x0", - value: 50000000000000000000 -} -``` - -Now that the user account is funded with ether, a contract can be created ready to deploy to the Geth node. - -## A simple smart contract - -This tutorial will make use of a classic example smart contract, `Storage.sol`. This contract exposes two public functions, one to add a value to the contract storage and one to view the stored value. The contract, written in Solidity, is provided below: - -```Solidity -pragma solidity >=0.7.0; - -contract Storage{ - - - uint256 number; - - function store(uint256 num) public{ - - number = num; - } - - function retrieve() public view returns (uint256){ - return number; - - } -} -``` - -Solidity is a high-level language that makes code executable by the Ethereum virtual machine (EVM) readable to humans. This means that there is an intermediate step between writing code in Solidity and deploying it to Ethereum. This step is called "compilation" and it converts human-readable code into EVM-executable byte-code. This byte-code is then included in a transaction sent from the Geth node during contract deployment. This can all be done directly from the Geth Javascript console; however this tutorial uses an online IDE called Remix to handle the compilation and deployment of the contract to the local Geth node. - -## Compile and deploy using Remix - -In a web browser, open . This opens an online smart contract development environment. On the left-hand side of the screen there is a side-bar menu that toggles between several toolboxes that are displayed in a vertical panel. On the right hand side of the screen there is an editor and a terminal. This layout is similar to the default layout of many other IDEs such as [VSCode](https://code.visualstudio.com/). The contract defined in the previous section, `Storage.sol` is already available in the `Contracts` directory in Remix. It can be opened and reviewed in the editor. - -![Remix](/assets/remix.png) - -The Solidity logo is present as an icon in the Remix side-bar. Clicking this icon opens the Solidity compiler wizard. This can be used to compile `Storage.sol` ready. With `Solidity.sol` open in the editor window, simply click the `Compile 1_Storage.sol` button. A green tick will appear next to the Solidity icon to confirm that the contract has compiled successfully. This means the contract bytecode is available. - -![Remix-compiler](assets/remix-compiler.png) - -Below the Solidity icon is a fourth icon that includes the Ethereum logo. Clicking this opens the Deploy menu. In this menu, Remix can be configured to connect to the local Geth node. In the drop-down menu labelled `ENVIRONMENT`, select `Injected Web3`. This will open an information pop-up with instructions for configuring Geth - these can be ignored as they were completed earlier in this tutorial. However, at the bottom of this pop-up is a box labelled `Web3 Provider Endpoint`. This should be set to Geth's 8545 port on `localhost` (`127.0.0.1:8545`). Click OK. The `ACCOUNT` field should automatically populate with the address of the account created earlier using the Geth Javascript console. - -![Remix-deploy](assets/remix-deploy.png) - -To deploy `Storage.sol`, click `DEPLOY`. - -The following logs in the Geth terminal confirm that the contract was successfully deployed. - -```terminal -INFO [05-09|12:27:09.680] Setting new local account address=0x7Aa16266Ba3d309e3cb278B452b1A6307E52Fb62 -INFO [05-09|12:27:09.680] Submitted contract creation hash=0xbf2d2d1c393a882ffb6c90e6d1713906fd799651ae683237223b897d4781c4f2 from=0x7Aa16266Ba3d309e3cb278B452b1A6307E52Fb62 nonce=1 contract=0x4aA11DdfD817dD70e9FF2A2bf9c0306e8EC450d3 value=0 -INFO [05-09|12:27:09.681] Commit new sealing work number=2 sealhash=845a53..f22818 uncles=0 txs=1 gas=125,677 fees=0.0003141925 elapsed="335.991µs" -INFO [05-09|12:27:09.681] Successfully sealed new block number=2 sealhash=845a53..f22818 hash=e927bc..f2c8ed elapsed="703.415µs" -INFO [05-09|12:27:09.681] 🔨 mined potential block number=2 hash=e927bc..f2c8ed -``` - -## Interact with contract using Remix - -The contract is now deployed on a local testnet version of the Etheruem blockchain. This means there is a contract address that contains executable bytecode that can be invoked by sending transactions with instructions, also in bytecode, to that address. Again, this can all be achieved by constructing transactions directly in the Geth console or even by making external http requests using tools such as Curl. Here, Remix is used to retrieve the value, then the same action is taken using the Javascript console. - -After deploying the contract in Remix, the `Deployed Contracts` tab in the sidebar automatically populates with the public functions exposed by `Storage.sol`. To send a value to the contract storage, type a number in the field adjacent to the `store` button, then click the button. - -![Remix-func](/assets/remix-func.png) - -In the Geth terminal, the following logs confirm that the transaction was successful (the actual values will vary from the example below): - -```terminal -INFO [05-09|13:41:58.644] Submitted transaction hash=0xfa3cd8df6841c5d3706d3bacfb881d2b985d0b55bdba440f1fdafa4ed5b5cc31 from=0x7Aa16266Ba3d309e3cb278B452b1A6307E52Fb62 nonce=2 recipient=0x4aA11DdfD817dD70e9FF2A2bf9c0306e8EC450d3 value=0 -INFO [05-09|13:41:58.644] Commit new sealing work number=3 sealhash=5442e3..f49739 uncles=0 txs=1 gas=43724 fees=0.00010931 elapsed="334.446µs" -INFO [05-09|13:41:58.645] Successfully sealed new block number=3 sealhash=5442e3..f49739 hash=c076c8..eeee77 elapsed="581.374µs" -INFO [05-09|13:41:58.645] 🔨 mined potential block number=3 hash=c076c8..eeee77 -``` - -The transaction hash can be used to retrieve the transaction details using the Geth Javascript console, which will return the following information: - -```terminal -{ - accessList: [], - blockHash: "0xc076c88200618f4cbbfb4fe7c3eb8d93566724755acc6c4e9a355cc090eeee77", - blockNumber: 3, - chainId: "0x539", - from: "0x7aa16266ba3d309e3cb278b452b1a6307e52fb62", - gas: 43724, - gasPrice: 3172359839, - hash: "0xfa3cd8df6841c5d3706d3bacfb881d2b985d0b55bdba440f1fdafa4ed5b5cc31", - input: "0x6057361d0000000000000000000000000000000000000000000000000000000000000038", - maxFeePerGas: 4032048134, - maxPriorityFeePerGas: 2500000000, - nonce: 2, - r: "0x859b88062715c5d66b9a188886ad51b68a1e4938d5932ce2dac874c104d2b26", - s: "0x61ef6bc454d5e6a76c414f133aeb6321197a61e263a3e270a16bd4a65d94da55", - to: "0x4aa11ddfd817dd70e9ff2a2bf9c0306e8ec450d3", - transactionIndex: 0, - type: "0x2", - v: "0x1", - value: 0 -} -``` - -The `from` address is the account that sent the transaction, the `to` address is the deployment address of the contract. The value entered into Remix is now in storage at that contract address. This can be retrieved using Remix by calling the `retrieve` function - to do this simply click the `retrieve` button. Alternatively, it can be retrieved using `web3.getStorageAt` using the Geth Javascript console. The following command returns the value in the contract storage (replace the given address with the correct one displayed in the Geth logs). - -```shell -web3.eth.getStorageAt("0x407d73d8a49eeb85d32cf465507dd71d507100c1", 0) -``` - -This returns a value that looks like the following: - -```terminal -"0x000000000000000000000000000000000000000000000000000000000000000038" -``` - -The returned value is a left-padded hexadecimal value. For example, the return value `0x000000000000000000000000000000000000000000000000000000000000000038` corresponds to a value of `56` entered as a uint256 to Remix. After converting from hexadecimal string to decimal number the returned value should be equal to that provided to Remix in the previous step. - -## Reusing --datadir - -This tutorial used an ephemeral blockchain that is completely destroyed and started afresh during each dev-mode session. However, it is also possible to create persistent blockchain and account data that can be reused across multiple sessions. This is done by providing the `--datadir` flag and a directory name when starting Geth in dev-mode. - -```shell -geth --datadir dev-chain --dev --http --http.api personal,web3,eth,net --http.corsdomain "remix.ethereum.org" -``` - -## Re-using accounts - -Geth will fail to start in dev-mode if keys have been manually created or imported into the keystore in the `--datadir` directory. This is because the account cannot be automatically unlocked. To resolve this issue, the password defined when the account was created can be saved to a text file and its path passed to the `--password` flag on starting Geth, for example if `password.txt` is saved in the top-level `go-ethereum` directory: - -```shell - -geth --datadir dev-chain --dev --http --http.api personal,web3,eth,net --http.corsdomain "remix.ethereum.org" --password password.txt - -``` - -**Note** that this is an edge-case that applies when both the `--datadir` and `--dev` flags are used and a key has been manually created or imported into the keystore. - -## Summary - -This tutorial has demonstrated how to spin up a local developer network using Geth. Having started this development network, a simple contract was deployed to the developer network. Then, Remix was connected to the local Geth node and used to deploy and interact with a contract. Remix was used to add a value to the contract storage and then the value was retrieved using Remix and also using the lower level commands in the Javascript console. diff --git a/content/docs/developers/geth-developer/devguide.md b/content/docs/developers/geth-developer/devguide.md deleted file mode 100644 index 8eb0c104f5..0000000000 --- a/content/docs/developers/geth-developer/devguide.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Getting Started -description: Entry point for developers working on Geth ---- - -This document is the entry point for developers who wish to work on Geth. Developers are people who are interested to build, develop, debug, submit -a bug report or pull request or otherwise contribute to the Geth source code. - -Please see [Contributing](/content/docs/developers/contributing.md) for the Geth contribution guidelines. - -## Building and Testing - -Developers should use a recent version of Go for building and testing. We use the go toolchain for development, which you can get from the [Go downloads page](https://golang.org/doc/install). Geth is a Go module, and uses the [Go modules system](https://github.com/golang/go/wiki/Modules) to manage dependencies. Using `GOPATH` is not required to build go-ethereum. - -### Building Executables - -Switch to the go-ethereum repository root directory. All code can be built using the go tool, placing the resulting binary in `$GOPATH/bin`. - -```text -go install -v ./... -``` - -go-ethereum exectuables can be built individually. To build just geth, use: - -```text -go install -v ./cmd/geth -``` - -Cross compilation is not recommended, please build Geth for the host architecture. - -### Testing - -Testing a package: - -``` -go test -v ./eth -``` - -Running an individual test: - -``` -go test -v ./eth -run TestMethod -``` - -**Note**: here all tests with prefix _TestMethod_ will be run, so if TestMethod and TestMethod1 both exist then both tests will run. - -Running benchmarks, eg.: - -``` -go test -v -bench . -run BenchmarkJoin -``` - -For more information, see the [go test flags](https://golang.org/cmd/go/#hdr-Testing_flags) documentation. - -### Stack Traces - -If Geth is started with the `--pprof` option, a debugging HTTP server is made available on port 6060. Navigating to displays the heap, running routines etc. By clicking "full goroutine stack dump" a trace can be generated that is useful for debugging. - -Note that if multiple instances of Geth exist, port `6060` will only work for the first instance that was launched. To generate stacktraces for other instances, they should be started up with alternative pprof ports. Ensure `stderr` is being redirected to a logfile. - -``` -geth -port=30300 -verbosity 5 --pprof --pprof.port 6060 2>> /tmp/00.glog -geth -port=30301 -verbosity 5 --pprof --pprof.port 6061 2>> /tmp/01.glog -geth -port=30302 -verbosity 5 --pprof --pprof.port 6062 2>> /tmp/02.glog -``` - -Alternatively to kill the clients (in case they hang or stalled syncing, etc) and have the stacktrace too, use the `-QUIT` signal with `kill`: - -``` -killall -QUIT geth -``` - -This will dump stack traces for each instance to their respective log file. - -## Where to go next - -Read the remaning pages in the Geth developer section, and get building! diff --git a/content/docs/developers/geth-developer/dns-discovery-setup.md b/content/docs/developers/geth-developer/dns-discovery-setup.md deleted file mode 100644 index 99882f961f..0000000000 --- a/content/docs/developers/geth-developer/dns-discovery-setup.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: DNS Discovery Setup Guide -description: Instructions for setting up DNS discovery ---- - -This document explains how to set up an [EIP 1459](https://eips.ethereum.org/EIPS/eip-1459) node list using the devp2p developer tool. The focus of this guide is creating a public list for the Ethereum mainnet and public testnets, but it may also be helpful for setting up DNS-based discovery for a private network. - -DNS-based node lists can serve as a fallback option when connectivity to the discovery DHT is unavailable. In this guide, node lists will be reated by crawling the discovery DHT, then publishing the resulting node sets under chosen DNS names. - -### Installing the devp2p command - -`cmd/devp2p` is a developer utility and is not included in the Geth distribution. You can install this command using `go get`: - -```shell -go get github.com/ethereum/go-ethereum/cmd/devp2p -``` - -To create a signing key, the `ethkey` utility is needed. - -```shell -go get github.com/ethereum/go-ethereum/cmd/ethkey -``` - -### Crawling the v4 DHT - -Our first step is to compile a list of all reachable nodes. The DHT crawler in cmd/devp2p is a batch process which runs for a set amount of time. You should should schedule this command to run at a regular interval. To create a node list, run - -```shell -devp2p discv4 crawl -timeout 30m all-nodes.json -``` - -This walks the DHT and stores the set of all found nodes in the `all-nodes.json` file. -Subsequent runs of the same command will revalidate previously discovered node records, -add newly-found nodes to the set, and remove nodes which are no longer alive. The quality -of the node set improves with each run because the number of revalidations is tracked -alongside each node in the set. - -### Creating sub-lists through filtering - -Once `all-nodes.json` has been created and the set contains a sizeable number of nodes, -useful sub-sets of nodes can be extracted using the `devp2p nodeset filter` command. This -command takes a node set file as argument and applies filters given as command-line flags. - -To create a filtered node set, first create a new directory to hold the output set. You -can use any directory name, though it's good practice to use the DNS domain name as the -name of this directory. - -```shell -mkdir mainnet.nodes.example.org -``` - -Then, to create the output set containing Ethereum mainnet nodes only, run - -```shell -devp2p nodeset filter all-nodes.json -eth-network mainnet > mainnet.nodes.example.org/nodes.json -``` - -The following filter flags are available: - -- `-eth-network ( mainnet | ropsten | rinkeby | goerli )` selects an Ethereum network. -- `-les-server` selects LES server nodes. -- `-ip ` restricts nodes to the given IP range. -- `-min-age ` restricts the result to nodes which have been live for the - given duration. - -### Creating DNS trees - -To turn a node list into a DNS node tree, the list needs to be signed. To do this, a key pair is required. To create the key file in the correct format, the cmd/ethkey utility should be used. Choose a strong password to encrypt the key on disk! - -```shell -ethkey generate dnskey.json -``` - -Now use `devp2p dns sign` to update the signature of the node list. If the list's directory name differs from the name it will be published at,specify the DNS name the using the `-domain` flag. This command will prompt for the key file password and update the tree signature. - -```shell -devp2p dns sign mainnet.nodes.example.org dnskey.json -``` - -The resulting DNS tree metadata is stored in the `mainnet.nodes.example.org/enrtree-info.json` file. - -### Publishing DNS trees - -Now that the tree is signed, it can be published to a DNS provider. cmd/devp2p currently supports publishing to CloudFlare DNS and Amazon Route53.TXT records can also be exported as a JSON file and published independently. - -To publish to CloudFlare, first create an API token in the management console. cmd/devp2p expects the API token in the `CLOUDFLARE_API_TOKEN` environment variable. Now use the following command to upload DNS TXT records via the CloudFlare API: - -```shell -devp2p dns to-cloudflare mainnet.nodes.example.org -``` - -Note that this command uses the domain name specified during signing. Any existing records below this name will be erased by cmd/devp2p. - -### Using DNS trees with Geth - -Once a tree is available through a DNS name, Geth can use it with the `--discovery.dns` command line flag. Node trees are referenced using the `enrtree://` URL scheme. The URL of the tree can be found in the `enrtree-info.json` file created by `devp2p dns sign`. Pass the URL as an argument to the flag in order to make use of the published tree. - -```shell -geth --discovery.dns "enrtree://AMBMWDM3J6UY3M32TMMROUNLX6Y3YTLVC3DC6HN2AVG5NHNSAXDW6@mainnet.nodes.example.org" -``` diff --git a/content/docs/developers/geth-developer/issue-handling-workflow.md b/content/docs/developers/geth-developer/issue-handling-workflow.md deleted file mode 100644 index a2c5f54f61..0000000000 --- a/content/docs/developers/geth-developer/issue-handling-workflow.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Issue Handling Workflow -description: Instructions for managing Github issues ---- - -### Draft proposal - -- Keep the number of open issues under 820 - -- Keep the ratio of open issues per all issues under 13% - -- Have 50 issues labelled [help wanted](https://github.com/ethereum/go-ethereum/labels/help%20wanted) and 50 [good first issue](https://github.com/ethereum/go-ethereum/labels/good%20first%20issue). - -- Use structured labels of the form `: