Revert "Move wiki pages to github pages (#18497)"
This reverts commit 40eb803de1
.
This commit is contained in:
parent
4a1c393894
commit
161b15f9e4
|
@ -1,2 +0,0 @@
|
||||||
_site/
|
|
||||||
Gemfile.lock
|
|
|
@ -1 +0,0 @@
|
||||||
geth.ethereum.org
|
|
33
Gemfile
33
Gemfile
|
@ -1,33 +0,0 @@
|
||||||
source "https://rubygems.org"
|
|
||||||
|
|
||||||
# Hello! This is where you manage which Jekyll version is used to run.
|
|
||||||
# When you want to use a different version, change it below, save the
|
|
||||||
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
|
|
||||||
#
|
|
||||||
# bundle exec jekyll serve
|
|
||||||
#
|
|
||||||
# This will help ensure the proper Jekyll version is running.
|
|
||||||
# Happy Jekylling!
|
|
||||||
#gem "jekyll", "~> 3.8.5"
|
|
||||||
|
|
||||||
# This is the default theme for new Jekyll sites. You may change this to anything you like.
|
|
||||||
gem "minima", "~> 2.0"
|
|
||||||
|
|
||||||
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
|
|
||||||
# uncomment the line below. To upgrade, run `bundle update github-pages`.
|
|
||||||
gem "github-pages", group: :jekyll_plugins
|
|
||||||
|
|
||||||
# If you have any plugins, put them here!
|
|
||||||
group :jekyll_plugins do
|
|
||||||
gem "jekyll-feed", "~> 0.6"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
|
||||||
gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
|
||||||
|
|
||||||
# Performance-booster for watching directories on Windows
|
|
||||||
gem "wdm", "~> 0.1.0" if Gem.win_platform?
|
|
||||||
|
|
||||||
group :development, :test do
|
|
||||||
gem "pry"
|
|
||||||
end
|
|
54
_config.yml
54
_config.yml
|
@ -1,54 +0,0 @@
|
||||||
repository: ethereum/go-ethereum
|
|
||||||
url: https://geth.ethereum.org
|
|
||||||
|
|
||||||
theme: minima
|
|
||||||
|
|
||||||
keep_files:
|
|
||||||
- static
|
|
||||||
|
|
||||||
favicon: /static/images/favicon.png
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
- scope:
|
|
||||||
path: ""
|
|
||||||
values:
|
|
||||||
layout: sidebar
|
|
||||||
- scope:
|
|
||||||
path: "*"
|
|
||||||
values:
|
|
||||||
root: "."
|
|
||||||
- scope:
|
|
||||||
path: "*/*"
|
|
||||||
values:
|
|
||||||
root: ".."
|
|
||||||
|
|
||||||
default_root: ".."
|
|
||||||
|
|
||||||
collections_dir: docs
|
|
||||||
collections:
|
|
||||||
install-and-build:
|
|
||||||
output: true
|
|
||||||
caption: Install and build
|
|
||||||
sidebar_index: 1
|
|
||||||
how-to:
|
|
||||||
output: true
|
|
||||||
caption: How to use
|
|
||||||
sidebar_index: 2
|
|
||||||
interface:
|
|
||||||
output: true
|
|
||||||
caption: Interface documentation
|
|
||||||
sidebar_index: 3
|
|
||||||
support:
|
|
||||||
output: true
|
|
||||||
caption: Issues and support
|
|
||||||
sidebar_index: 4
|
|
||||||
developers:
|
|
||||||
output: true
|
|
||||||
caption: Developers
|
|
||||||
sidebar_index: 5
|
|
||||||
doc:
|
|
||||||
output: true
|
|
||||||
caption: Other
|
|
||||||
sidebar_index: 6
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
Install: /doc/Installing-Geth
|
|
||||||
Downloads: /downloads
|
|
||||||
Documentation: /docs
|
|
|
@ -1,23 +0,0 @@
|
||||||
Install and build:
|
|
||||||
- Downloads: /downloads
|
|
||||||
- Installing Ethereum: /docs/Building-Ethereum
|
|
||||||
- Developers' Guide: /docs/Developers-Guide
|
|
||||||
How to use:
|
|
||||||
- Managing Accounts: /docs/Managing-your-accounts
|
|
||||||
- Mining: /docs/Mining
|
|
||||||
- Contract Tutorial: /docs/Contract-Tutorial
|
|
||||||
Interface Documentation:
|
|
||||||
- Command Line Options: /docs/Command-Line-Options
|
|
||||||
- JavaScript Console: /docs/JavaScript-Console
|
|
||||||
- Management API: /docs/Management-APIs
|
|
||||||
- JSON-RPC server: https://github.com/ethereum/wiki/wiki/JSON-RPC
|
|
||||||
Issues and support:
|
|
||||||
- FAQ: /docs/FAQ
|
|
||||||
- Reporting issues: /docs/geth#reporting
|
|
||||||
- Community and support: /docs/geth#community-and-support
|
|
||||||
- Issue handling workflow: /docs/Issue-handling-workflow
|
|
||||||
Developers:
|
|
||||||
- Mobile Clients: /docs/Mobile-Clients/Libraries-and-Inproc-Ethereum-Nodes
|
|
||||||
- Native DApps: /docs/Native-DApps/Go-bindings-to-Ethereum-contracts
|
|
||||||
- Active go-ethereum projects: /docs/Active-go-ethereum-projects
|
|
||||||
- Other documents: /docs/other-documents
|
|
|
@ -1,34 +0,0 @@
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
<title>{% if page.title %}{{ page.title }} | {% endif %}Go Ethereum</title>
|
|
||||||
<!-- debug root:{% include link.html url="/debug-path" %} -->
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="{% include link.html url=site.favicon %}" />
|
|
||||||
{% if layout.common-css %}
|
|
||||||
{% for css in layout.common-css %}
|
|
||||||
<link rel="stylesheet" href="{% include link.html url=css %}" />
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if page.css %}
|
|
||||||
{% for css in page.css %}
|
|
||||||
<link rel="stylesheet" href="{% include link.html url=css %}" />
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if layout.common-js %}
|
|
||||||
{% for js in layout.common-js %}
|
|
||||||
<script src="{% include link.html url=js %}"></script>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if page.js %}
|
|
||||||
{% for js in page.js %}
|
|
||||||
<script src="{% include link.html url=js %}"></script>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</head>
|
|
|
@ -1,2 +0,0 @@
|
||||||
{% capture root %}{% if page.root %}{{ page.root }}{% else %}{{ site.default_root }}{% endif %}{% endcapture %}
|
|
||||||
{{ include.url | remove: ".html" | prepend: root | replace: '//', '/' }}
|
|
|
@ -1 +0,0 @@
|
||||||
{{ include.doc.title | remove_first: include.coll.label | remove_first: "/ " }}
|
|
|
@ -1,48 +0,0 @@
|
||||||
---
|
|
||||||
common-css:
|
|
||||||
- /static/styles/bootstrap.min.css
|
|
||||||
- /static/styles/flatly.min.css
|
|
||||||
- /static/styles/font-awesome.min.css
|
|
||||||
- /static/styles/custom/common.css
|
|
||||||
common-js:
|
|
||||||
- /static/scripts/jquery.min.js
|
|
||||||
- /static/scripts/bootstrap.min.js
|
|
||||||
- /static/scripts/moment.min.js
|
|
||||||
- /static/scripts/marked.min.js
|
|
||||||
- /static/scripts/emojify.min.js
|
|
||||||
- /static/scripts/custom/polyfills.js
|
|
||||||
---
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
{% include head.html %}
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<nav class="navbar navbar-default navbar-fixed-top">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="{% include link.html url='/' %}/">Go Ethereum</a>
|
|
||||||
</div>
|
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
{% for link in site.data.navbar %}
|
|
||||||
<li>
|
|
||||||
<a href="{% include link.html url=link.last %}">{{ link.first }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
{{ content }}
|
|
||||||
<hr/>
|
|
||||||
<footer class="container">
|
|
||||||
<p>© 2013-2019. The go-ethereum Authors.</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
---
|
|
||||||
<div class="container" style="padding-top: 24px;">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3" id="toc" style="padding-top: 16px;">
|
|
||||||
{% assign collections = site.collections | sort: "sidebar_index" %}
|
|
||||||
{% for coll in collections %}
|
|
||||||
{% if coll.sidebar_index %}
|
|
||||||
{% assign count = coll.docs | size %}
|
|
||||||
{% if count <= 5 %}
|
|
||||||
<div class="list-group">
|
|
||||||
<a class="list-group-item active">{{ coll.caption }}</a>
|
|
||||||
{% for doc in coll.docs %}
|
|
||||||
<a class="list-group-item"
|
|
||||||
href="{% include link.html url=doc.url %}">
|
|
||||||
{% include title.html doc=doc coll=coll %}</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
{% capture url %}/{{ coll.label }}{% endcapture %}
|
|
||||||
<div class="list-group">
|
|
||||||
<a class="list-group-item active"
|
|
||||||
href="{% include link.html url=url %}">{{ coll.caption }}</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-9" id="content">
|
|
||||||
{% if page.title %}
|
|
||||||
<h1 class="featurette-heading">{% include title.html doc=page coll=page.collection %}</h1>
|
|
||||||
{% endif %}
|
|
||||||
{{ content }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
8
doc.md
8
doc.md
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
title: Other documents
|
|
||||||
root: ..
|
|
||||||
permalink: /doc/
|
|
||||||
---
|
|
||||||
{% for p in site.doc %}
|
|
||||||
* [{{ p.title }}]({% include link.html url=p.url %})
|
|
||||||
{% endfor %}
|
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
title: Active go-ethereum projects
|
|
||||||
---
|
|
||||||
## Direction of development until the end of 2018
|
|
||||||
|
|
||||||
- Clef: move account management out of geth to clef
|
|
||||||
- Constantinople - Tools for testing
|
|
||||||
- Automate cross-client testing
|
|
||||||
- Progpow (ASIC-resistent PoW algorithm)
|
|
||||||
- Ethereum Node Report
|
|
||||||
- Topic discovery
|
|
||||||
- Build an end-to-end test system
|
|
||||||
- Simple API for LES-protocol
|
|
||||||
- Loadbalance tests using Swarm team's network simulator
|
|
||||||
- Test FlowControl subsystem rewrite
|
|
||||||
- Clients get more bandwidth with micro-payment
|
|
||||||
- Database IO reductions
|
|
||||||
- Historical state pruning
|
|
||||||
- Next gen sync algo (cross client)
|
|
||||||
- Blockscout for Puppeth
|
|
||||||
- Contract based signers for Clique (v1.5)
|
|
||||||
- Rinkeby - improve maintenance
|
|
||||||
- Concurrent tx execution experiment
|
|
||||||
- Dashboard
|
|
||||||
- Hive - Devp2p basic tests running as Hive simulation
|
|
||||||
- Hive - Devp2p network tests (different clients peering)
|
|
||||||
- Hive - Add all known client implementations
|
|
||||||
- Hive - Public metrics/test failures page
|
|
||||||
- DevP2P - Document protocols
|
|
||||||
- Hive - Further tests for networked consensus
|
|
||||||
- Discovery - Work with Felix to get ENR/next discovery out asap
|
|
||||||
- Countable trie experiment - For better sync statistic and futher storage rent
|
|
||||||
- Build an end-to-end test system
|
|
||||||
- Finalize simple checkpoint syncing
|
|
|
@ -1,441 +0,0 @@
|
||||||
---
|
|
||||||
title: Native DApps / Go bindings to Ethereum contracts
|
|
||||||
---
|
|
||||||
**[Please note, events are not yet implemented as they need some RPC subscription
|
|
||||||
features that are still under review.]**
|
|
||||||
|
|
||||||
The original roadmap and/or dream of the Ethereum platform was to provide a solid, high
|
|
||||||
performing client implementation of the consensus protocol in various languages, which
|
|
||||||
would provide an RPC interface for JavaScript DApps to communicate with, pushing towards
|
|
||||||
the direction of the Mist browser, through which users can interact with the blockchain.
|
|
||||||
|
|
||||||
Although this was a solid plan for mainstream adoption and does cover quite a lot of use
|
|
||||||
cases that people come up with (mostly where people manually interact with the blockchain),
|
|
||||||
it eludes the server side (backend, fully automated, devops) use cases where JavaScript is
|
|
||||||
usually not the language of choice given its dynamic nature.
|
|
||||||
|
|
||||||
This page introduces the concept of server side native Dapps: Go language bindings to any
|
|
||||||
Ethereum contract that is compile time type safe, highly performant and best of all, can
|
|
||||||
be generated fully automatically from a contract ABI and optionally the EVM bytecode.
|
|
||||||
|
|
||||||
*This page is written in a more beginner friendly tutorial style to make it easier for
|
|
||||||
people to start out with writing Go native Dapps. The used concepts will be introduced
|
|
||||||
gradually as a developer would need/encounter them. However, we do assume the reader
|
|
||||||
is familiar with Ethereum in general, has a fair understanding of Solidity and can code
|
|
||||||
Go.*
|
|
||||||
|
|
||||||
## Token contract
|
|
||||||
|
|
||||||
To avoid falling into the fallacy of useless academic examples, we're going to take the
|
|
||||||
official [Token contract](https://ethereum.org/token) as the base for introducing the Go
|
|
||||||
native bindings. If you're unfamiliar with the contract, skimming the linked page should
|
|
||||||
probably be enough, the details aren't relevant for now. *In short the contract implements
|
|
||||||
a custom token that can be deployed on top of Ethereum.* To make sure this tutorial doesn't
|
|
||||||
go stale if the linked website changes, the Solidity source code of the Token contract is
|
|
||||||
also available at [`token.sol`](https://gist.github.com/karalabe/08f4b780e01c8452d989).
|
|
||||||
|
|
||||||
### Go binding generator
|
|
||||||
|
|
||||||
Interacting with a contract on the Ethereum blockchain from Go (or any other language for
|
|
||||||
a matter of fact) is already possible via the RPC interfaces exposed by Ethereum clients.
|
|
||||||
However, writing the boilerplate code that translates decent Go language constructs into
|
|
||||||
RPC calls and back is extremely time consuming and also extremely 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 can be painful to port over to Go.
|
|
||||||
|
|
||||||
To avoid all this mess, the go-ethereum implementation introduces a source code generator
|
|
||||||
that can convert Ethereum ABI definitions into easy to use, type-safe Go packages. Assuming
|
|
||||||
you have a valid Go development environment set up, `godep` installed and the go-ethereum
|
|
||||||
repository checked out correctly, you can build the generator with:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cd $GOPATH/src/github.com/ethereum/go-ethereum
|
|
||||||
$ godep go install ./cmd/abigen
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generating the bindings
|
|
||||||
|
|
||||||
The single essential thing needed to generate a Go binding to an Ethereum contract is the
|
|
||||||
contract's ABI definition `JSON` file. For our `Token` contract tutorial you can obtain this
|
|
||||||
either by compiling the Solidity code yourself (e.g. via @chriseth's [online Solidity compiler](https://chriseth.github.io/browser-solidity/)), or you can download our pre-compiled [`token.abi`](https://gist.github.com/karalabe/b8dfdb6d301660f56c1b).
|
|
||||||
|
|
||||||
To generate a binding, simply call:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ abigen --abi token.abi --pkg main --type Token --out token.go
|
|
||||||
```
|
|
||||||
|
|
||||||
Where the flags are:
|
|
||||||
|
|
||||||
* `--abi`: Mandatory path to the contract ABI to bind to
|
|
||||||
* `--pgk`: 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 Token contract. The generated code will
|
|
||||||
look something like [`token.go`](https://gist.github.com/karalabe/5839509295afa4f7e2215bc4116c7a8f),
|
|
||||||
but please generate your own as this will change as more work is put into the generator.
|
|
||||||
|
|
||||||
### Accessing an Ethereum contract
|
|
||||||
|
|
||||||
To interact with a contract deployed on the blockchain, you'll need to know the `address`
|
|
||||||
of the contract itself, and need to specify a `backend` through which to access Ethereum.
|
|
||||||
The binding generator provides out of the box an RPC backend through which you can attach
|
|
||||||
to an existing Ethereum node via IPC, HTTP or WebSockets.
|
|
||||||
|
|
||||||
We'll use the foundation's [Unicorn](https://ethereum.org/donate) token contract deployed
|
|
||||||
on the testnet to demonstrate calling contract methods. It is deployed at the address
|
|
||||||
`0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576`.
|
|
||||||
|
|
||||||
To run the snippet below, please ensure a Geth instance is running and attached to the
|
|
||||||
Morden test network where the above mentioned contract was deployed. Also please update
|
|
||||||
the path to the IPC socket below to the one reported by your own local Geth node.
|
|
||||||
|
|
||||||
```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
|
|
||||||
conn, err := ethclient.Dial("/home/karalabe/.ethereum/testnet/geth.ipc")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
|
|
||||||
}
|
|
||||||
// Instantiate the contract and display its name
|
|
||||||
token, err := NewToken(common.HexToAddress("0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576"), conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to instantiate a Token contract: %v", err)
|
|
||||||
}
|
|
||||||
name, err := token.Name(nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to retrieve token name: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println("Token name:", name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And the output (yay):
|
|
||||||
|
|
||||||
```
|
|
||||||
Token name: Testnet Unicorn
|
|
||||||
```
|
|
||||||
|
|
||||||
If you look at the method invoked to read the token name `token.Name(nil)`, it required
|
|
||||||
a parameter to be passed, even though the original Solidity contract requires none. This
|
|
||||||
is a `*bind.CallOpts` type, which can be used to fine tune the call.
|
|
||||||
|
|
||||||
* `Pending`: Whether to access pending contract state or the current stable one
|
|
||||||
* `GasLimit`: Place a limit on the computing resources the call might consume
|
|
||||||
|
|
||||||
### 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. **Opposed
|
|
||||||
to the conventional way of storing accounts and keys in the node we attach to, Go bindings
|
|
||||||
require signing transactions locally and do not delegate this to a remote node.** This is
|
|
||||||
done so to facilitate the general direction of the Ethereum community where accounts are
|
|
||||||
kept private to 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 himself.
|
|
||||||
|
|
||||||
Changing the previous code snippet to send one unicorn to the zero address:
|
|
||||||
|
|
||||||
```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 = `paste the contents of your *testnet* key json here`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create an IPC based RPC connection to a remote node and instantiate a contract binding
|
|
||||||
conn, err := ethclient.Dial("/home/karalabe/.ethereum/testnet/geth.ipc")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
|
|
||||||
}
|
|
||||||
token, err := NewToken(common.HexToAddress("0x21e6fc92f93c8a1bb41e2be64b4e1f88a54d3576"), conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to instantiate a Token contract: %v", err)
|
|
||||||
}
|
|
||||||
// Create an authorized transactor and spend 1 unicorn
|
|
||||||
auth, err := bind.NewTransactor(strings.NewReader(key), "my awesome super secret password")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to create authorized transactor: %v", err)
|
|
||||||
}
|
|
||||||
tx, err := token.Transfer(auth, common.HexToAddress("0x0000000000000000000000000000000000000000"), big.NewInt(1))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to request token transfer: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("Transfer pending: 0x%x\n", tx.Hash())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And the output (yay):
|
|
||||||
|
|
||||||
```
|
|
||||||
Transfer pending: 0x4f4aaeb29ed48e88dd653a81f0b05d4df64a86c99d4e83b5bfeb0f0006b0e55b
|
|
||||||
```
|
|
||||||
|
|
||||||
*Note, with high probability you won't have any testnet unicorns available to spend, so the
|
|
||||||
above program will fail with an error. Send at least 2.014 testnet(!) Ethers to the foundation
|
|
||||||
testnet tipjar `0xDf7D0030bfed998Db43288C190b63470c2d18F50` to receive a unicorn token and
|
|
||||||
you'll be able to see the above code run without an error!*
|
|
||||||
|
|
||||||
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. An unset value is assumed to be zero.
|
|
||||||
|
|
||||||
### Pre-configured contract sessions
|
|
||||||
|
|
||||||
As mentioned in the previous two sections, both reading as well as state modifying contract
|
|
||||||
calls require a mandatory first parameter which can both authorize as well as fine tune some
|
|
||||||
of the internal parameters. However, most of the time we want to use the same parameters and
|
|
||||||
issue transactions with the same account, so always constructing the call/transact options or
|
|
||||||
passing them along with the binding can become unwieldy.
|
|
||||||
|
|
||||||
To avoid these scenarios, 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 analogous to the original contract type name, just suffixed with `Sessions`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Wrap the Token contract instance into a session
|
|
||||||
session := &TokenSession{
|
|
||||||
Contract: token,
|
|
||||||
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.Name()
|
|
||||||
session.Transfer("0x0000000000000000000000000000000000000000"), big.NewInt(1))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deploying contracts to Ethereum
|
|
||||||
|
|
||||||
Interacting with existing contracts is nice, but let's take it up a notch and deploy
|
|
||||||
a brand new contract onto the Ethereum blockchain! To do so however, the contract ABI
|
|
||||||
we used to generate the binding is not enough. We need the compiled bytecode too to
|
|
||||||
allow deploying it.
|
|
||||||
|
|
||||||
To get the bytecode, either go back to the online compiler with which you may generate it,
|
|
||||||
or alternatively download our [`token.bin`](https://gist.github.com/karalabe/026548f6a5f5f97b54de).
|
|
||||||
You'll need to rerun the Go generator with the bytecode included for it to create deploy
|
|
||||||
code too:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ abigen --abi token.abi --pkg main --type Token --out token.go --bin token.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
This will generate something similar to [`token.go`](https://gist.github.com/karalabe/2153b087c1f80f651fd87dd4c439fac4).
|
|
||||||
If you quickly skim this file, you'll find an extra `DeployToken` function that was just
|
|
||||||
injected compared to the previous code. Beside all the parameters specified by Solidity,
|
|
||||||
it also needs the usual authorization options to deploy the contract with and the Ethereum
|
|
||||||
backend to deploy the contract through.
|
|
||||||
|
|
||||||
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 = `paste the contents of your *testnet* key json here`
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Create an IPC based RPC connection to a remote node and an authorized transactor
|
|
||||||
conn, err := rpc.NewIPCClient("/home/karalabe/.ethereum/testnet/geth.ipc")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
|
|
||||||
}
|
|
||||||
auth, err := bind.NewTransactor(strings.NewReader(key), "my awesome super secret password")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to create authorized transactor: %v", err)
|
|
||||||
}
|
|
||||||
// Deploy a new awesome contract for the binding demo
|
|
||||||
address, tx, token, err := DeployToken(auth, conn), new(big.Int), "Contracts in Go!!!", 0, "Go!")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to deploy new token 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())
|
|
||||||
|
|
||||||
// Don't even wait, check its presence in the local pending state
|
|
||||||
time.Sleep(250 * time.Millisecond) // Allow it to be processed by the local node :P
|
|
||||||
|
|
||||||
name, err := token.Name(&bind.CallOpts{Pending: true})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to retrieve pending name: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println("Pending name:", name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And the code performs as expected: it requests the creation of a brand new Token contract
|
|
||||||
on the Ethereum blockchain, which we can either wait for to be mined or as in the above code
|
|
||||||
start calling methods on it in the pending state :)
|
|
||||||
|
|
||||||
```
|
|
||||||
Contract pending deploy: 0x46506d900559ad005feb4645dcbb2dbbf65e19cc
|
|
||||||
Transaction waiting to be mined: 0x6a81231874edd2461879b7280ddde1a857162a744e3658ca7ec276984802183b
|
|
||||||
|
|
||||||
Pending name: Contracts in Go!!!
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bind Solidity directly
|
|
||||||
|
|
||||||
If you've followed the tutorial along until this point you've probably realized that
|
|
||||||
every contract modification needs to be recompiled, the produced ABIs and bytecodes
|
|
||||||
(especially if you need multiple contracts) individually saved to files and then the
|
|
||||||
binding executed for them. This can become a quite bothersome after the Nth iteration,
|
|
||||||
so the `abigen` command supports binding from Solidity source files directly (`--sol`),
|
|
||||||
which first compiles the source code (via `--solc`, defaulting to `solc`) into it's
|
|
||||||
constituent components and binds using that.
|
|
||||||
|
|
||||||
Binding the official Token contract [`token.sol`](https://gist.github.com/karalabe/08f4b780e01c8452d989)
|
|
||||||
would then entail to running:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ abigen --sol token.sol --pkg main --out token.go
|
|
||||||
```
|
|
||||||
|
|
||||||
*Note: Building from Solidity (`--sol`) is mutually exclusive with individually setting
|
|
||||||
the bind components (`--abi`, `--bin` and `--type`), as all of them are extracted from
|
|
||||||
the Solidity code and produced build results directly.*
|
|
||||||
|
|
||||||
Building a contract directly from Solidity has the nice side effect that all contracts
|
|
||||||
contained within a Solidity source file are built and bound, so if your file contains many
|
|
||||||
contract sources, each and every one of them will be available from Go code. The sample
|
|
||||||
Token solidity file results in [`token.go`](https://gist.github.com/karalabe/c22aab73194ba7da834ab5b379621031).
|
|
||||||
|
|
||||||
### Project integration (i.e. `go generate`)
|
|
||||||
|
|
||||||
The `abigen` command was made in such a way as to play beautifully together with existing
|
|
||||||
Go toolchains: instead of having to remember the exact command needed to bind an Ethereum
|
|
||||||
contract into a Go project, we can leverage `go generate` to remember all the nitty-gritty
|
|
||||||
details.
|
|
||||||
|
|
||||||
Place the binding generation command into a Go source file before the package definition:
|
|
||||||
|
|
||||||
```
|
|
||||||
//go:generate abigen --sol token.sol --pkg main --out token.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 already deployed Ethereum contracts from within native Go
|
|
||||||
code is an extremely powerful feature, but there is one facet with developing native code
|
|
||||||
that not even the testnet lends itself well to: *automatic unit testing*. Using go-ethereum
|
|
||||||
internal constructs it's possible to create test chains and verify them, but it is unfeasible
|
|
||||||
to do high level contract testing with such low level mechanisms.
|
|
||||||
|
|
||||||
To sort out this last issue that would make it hard to run (and test) native DApps, we've also
|
|
||||||
implemented a *simulated blockchain*, that can be set as a backend to native contracts the same
|
|
||||||
way as a live RPC backend could be: `backends.NewSimulatedBackend(genesisAccounts)`.
|
|
||||||
|
|
||||||
```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)})
|
|
||||||
|
|
||||||
// Deploy a token contract on the simulated blockchain
|
|
||||||
_, _, token, err := DeployMyToken(auth, sim, new(big.Int), "Simulated blockchain tokens", 0, "SBT")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to deploy new token contract: %v", err)
|
|
||||||
}
|
|
||||||
// Print the current (non existent) and pending name of the contract
|
|
||||||
name, _ := token.Name(nil)
|
|
||||||
fmt.Println("Pre-mining name:", name)
|
|
||||||
|
|
||||||
name, _ = token.Name(&bind.CallOpts{Pending: true})
|
|
||||||
fmt.Println("Pre-mining pending name:", name)
|
|
||||||
|
|
||||||
// Commit all pending transactions in the simulator and print the names again
|
|
||||||
sim.Commit()
|
|
||||||
|
|
||||||
name, _ = token.Name(nil)
|
|
||||||
fmt.Println("Post-mining name:", name)
|
|
||||||
|
|
||||||
name, _ = token.Name(&bind.CallOpts{Pending: true})
|
|
||||||
fmt.Println("Post-mining pending name:", name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And the output (yay):
|
|
||||||
|
|
||||||
```
|
|
||||||
Pre-mining name:
|
|
||||||
Pre-mining pending name: Simulated blockchain tokens
|
|
||||||
Post-mining name: Simulated blockchain tokens
|
|
||||||
Post-mining pending name: Simulated blockchain tokens
|
|
||||||
```
|
|
||||||
|
|
||||||
Note, that we don't have to wait for a local private chain miner, or testnet miner to
|
|
||||||
integrate the currently pending transactions. When we decide to mine the next block,
|
|
||||||
we simply `Commit()` the simulator.
|
|
|
@ -1,91 +0,0 @@
|
||||||
---
|
|
||||||
title: Mobile Clients
|
|
||||||
---
|
|
||||||
**This page has been obsoleted. An new guide is in the progress at [[Mobile: Introduction]]**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*This page is meant to be a guide on using go-ethereum from mobile platforms. Since neither the mobile libraries nor the light client protocol is finalized, the content here will be sparse, with emphasis being put on how to get your hands dirty. As the APIs stabilize this section will be expanded accordingly.*
|
|
||||||
|
|
||||||
### Changelog
|
|
||||||
|
|
||||||
* 30th September, 2016: Create initial page, upload Android light bundle.
|
|
||||||
|
|
||||||
### Background
|
|
||||||
|
|
||||||
Before reading further, please skim through the slides of a Devcon2 talk: [Import Geth: Ethereum from Go and beyond](https://ethereum.karalabe.com/talks/2016-devcon.html), which introduces the basic concepts behind using go-ethereum as a library, and also showcases a few code snippets on how you can do various client side tasks, both on classical computing nodes as well as Android devices. A recording of the talk will be linked when available.
|
|
||||||
|
|
||||||
*Please note, the Android and iOS library bundles linked in the presentation will not be updated (for obvious posterity reasons), so always grab latest bundles from this page (until everything is merged into the proper build infrastructure).*
|
|
||||||
|
|
||||||
### Mobile bundles
|
|
||||||
|
|
||||||
You can download the latest bundles at:
|
|
||||||
|
|
||||||
* [Android (30th September, 2016)](https://bintray.com/karalabe/ethereum/download_file?file_path=geth.aar) - `SHA1: 753e334bf61fa519bec83bcb487179e36d58fc3a`
|
|
||||||
* iOS: *light client has not yet been bundled*
|
|
||||||
|
|
||||||
### Android quickstart
|
|
||||||
|
|
||||||
We assume you are using Android Studio for your development. Please download the latest Android `.aar` bundle from above and import it into your Android Studio project via `File -> New -> New Module`. This will result in a `geth` sub-project inside your work-space. To use the library in your project, please modify your apps `build.gradle` file, adding a dependency to the Geth library:
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
dependencies {
|
|
||||||
// All your previous dependencies
|
|
||||||
compile project(':geth')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To get you hands dirty, here's a code snippet that will
|
|
||||||
|
|
||||||
* Start up an in-process light node inside your Android application
|
|
||||||
* Display some initial infos about your node
|
|
||||||
* Subscribe to new blocks and display them live as they arrive
|
|
||||||
|
|
||||||
<img src="http://i.imgur.com/LyTCCqg.png" width="512px" />
|
|
||||||
|
|
||||||
```java
|
|
||||||
import org.ethereum.geth.*;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
|
|
||||||
setTitle("Android In-Process Node");
|
|
||||||
final TextView textbox = (TextView) findViewById(R.id.textbox);
|
|
||||||
|
|
||||||
Context ctx = new Context();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Node node = Geth.newNode(getFilesDir() + "/.ethereum", new NodeConfig());
|
|
||||||
node.start();
|
|
||||||
|
|
||||||
NodeInfo info = node.getNodeInfo();
|
|
||||||
textbox.append("My name: " + info.getName() + "\n");
|
|
||||||
textbox.append("My address: " + info.getListenerAddress() + "\n");
|
|
||||||
textbox.append("My protocols: " + info.getProtocols() + "\n\n");
|
|
||||||
|
|
||||||
EthereumClient ec = node.getEthereumClient();
|
|
||||||
textbox.append("Latest block: " + ec.getBlockByNumber(ctx, -1).getNumber() + ", syncing...\n");
|
|
||||||
|
|
||||||
NewHeadHandler handler = new NewHeadHandler() {
|
|
||||||
@Override public void onError(String error) { }
|
|
||||||
@Override public void onNewHead(final Header header) {
|
|
||||||
MainActivity.this.runOnUiThread(new Runnable() {
|
|
||||||
public void run() { textbox.append("#" + header.getNumber() + ": " + header.getHash().getHex().substring(0, 10) + ".\n"); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ec.subscribeNewHead(ctx, handler, 16);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Known quirks
|
|
||||||
|
|
||||||
* Many constructors (those that would throw exceptions) are of the form `Geth.newXXX()`, instead of simply the Java style `new XXX()` This is an upstream limitation of the [gomobile](https://github.com/golang/mobile) project, one which is currently being worked on to resolve.
|
|
||||||
* There are zero documentations attached to the Java library methods. This too is a limitation of the [gomobile](https://github.com/golang/mobile) project. We will try to propose a fix upstream to make our docs from the Go codebase available in Java.
|
|
|
@ -1,74 +0,0 @@
|
||||||
---
|
|
||||||
title: Accounts
|
|
||||||
---
|
|
||||||
**THIS PAGE IS PARTLY OUTDATED! TODO: REFACTOR OR DELETE**
|
|
||||||
|
|
||||||
# Accounts / key storage specification
|
|
||||||
|
|
||||||
This is an attempt to compile a single, written specification from the multiple sources which have so far been used for accounts / key storage specs:
|
|
||||||
|
|
||||||
* Skype calls
|
|
||||||
* Skype chats
|
|
||||||
* Email conversations
|
|
||||||
* Github issues
|
|
||||||
* Github pull request comments
|
|
||||||
* Github commits
|
|
||||||
* Lively in-person discussions in the Amsterdam office.
|
|
||||||
* Several past instances of the Amsterdam office whiteboard contents.
|
|
||||||
|
|
||||||
# Background
|
|
||||||
|
|
||||||
Up until Ethereum PoC 8, the Go client has used a single, default key in plaintext on disk for use as wallet and for signing all txs. We want to extend this to have a more generic key storage supporting multiple keys. We also want an "accounts" abstraction over these keys where an account corresponds to a key, and a user can have multiple accounts and be able to send / receive to any of them.
|
|
||||||
|
|
||||||
The goal of this is to support better wallet / account functionality both in Mist as well as in DAPPs.
|
|
||||||
|
|
||||||
# Specification
|
|
||||||
|
|
||||||
## Key Storage
|
|
||||||
|
|
||||||
The key storage must support:
|
|
||||||
|
|
||||||
1. Generation of new keys
|
|
||||||
2. Deletion of keys.
|
|
||||||
3. Multiple, uniquely identifiable keys.
|
|
||||||
4. Password protection of keys.
|
|
||||||
5. Persistence of keys (e.g. on disk)
|
|
||||||
6. Export & Import of keys.
|
|
||||||
7. Import of pre-sale keys (generated by https://github.com/ethereum/pyethsaletool) NOTE: this is a different import functionality than general import (6)
|
|
||||||
8. Proper use of secure cryptography for key generation, password protection, key persistence and export format of keys.
|
|
||||||
9. Mechanism for Backing the keys up – maybe automatically
|
|
||||||
|
|
||||||
## Account Manager
|
|
||||||
|
|
||||||
0. Account == address of an Ethereum account == address of EC public key of EC private key the user controls.
|
|
||||||
|
|
||||||
The account manager must support:
|
|
||||||
|
|
||||||
1. Account creation & deletion
|
|
||||||
2. Multiple, unique accounts.
|
|
||||||
3. Persistence of accounts (e.g. on disk)
|
|
||||||
4. An account is mapped to a single key.
|
|
||||||
5. The account is identifiable by some public, non-sensitive data. E.g. the Ethereum address of a EC keypair can be used as account identifier / address.
|
|
||||||
|
|
||||||
## Mist
|
|
||||||
|
|
||||||
The Mist UI must support:
|
|
||||||
|
|
||||||
1. Creation of a new account.
|
|
||||||
2. Display a list of all available accounts (addresses)
|
|
||||||
3. Copy-paste of account addresses to easily use when receiving funds.
|
|
||||||
4. Choosing one of the available accounts when sending a tx.
|
|
||||||
5. Typing password when accessing one of the hot wallet keys
|
|
||||||
6. Showing the possible ways to temporarily input wallet keys when needed
|
|
||||||
|
|
||||||
## RPC API
|
|
||||||
|
|
||||||
The RPC API must support:
|
|
||||||
|
|
||||||
1. The list of accounts is exposed through the eth_accounts API: https://github.com/ethereum/wiki/JSON-RPC#eth_accounts
|
|
||||||
2. Using any of the available accounts as from/sender with the eth_transact API: https://github.com/ethereum/wiki/JSON-RPC#eth_transact (NOTE: the current API definition on that wiki page does not include a from/sender field!)
|
|
||||||
|
|
||||||
|
|
||||||
## Wallet DAPP
|
|
||||||
|
|
||||||
TODO:
|
|
|
@ -1,52 +0,0 @@
|
||||||
---
|
|
||||||
title: Achieving Darkness
|
|
||||||
---
|
|
||||||
Whisper is designed to be a building block in the next generation of unstoppable ÐApps. It was designed to provide resilience and privacy at considerable expense. At its most secure mode of operation Whisper can theoretically deliver complete darkness. Whisper should also allow the users to configure the level of privacy (how much information it leaks concerning the ÐApp content and ultimately, user activities) as a trade-off for performance. In this article we will discuss the strategy of achieving complete darkness.
|
|
||||||
|
|
||||||
### Adversary
|
|
||||||
|
|
||||||
In the worst case, you are playing against a very powerful adversary, which has a capacity to run a lot of Whisper nodes. In addition to that, it might generate Whisper identities in order to target a specific node. For example, it might generate IDs that will be very close to the ID of the target node, which then fit into Kademlia topology in such a way that will allow a traffic analysis from this node. As a result, it will be possible to see which messages originate from the target node.
|
|
||||||
|
|
||||||
### Recipient vs. Sender
|
|
||||||
|
|
||||||
Even if most nodes of the network belong to adversary, it will be still impossible to identify the recipient of particular message by the means of simple traffic analysis. But the sender might be identified. In order to prevent that, the node might maintain a certain noise level. For example, if the node sends on average several messages per hour, it might still send random messages every minute. Those extra messages should resemble the meaningful messages, but should contain randomly generated bytes and be encrypted with random key, so that adversary will not be able to distinguish the meaningful messages from the noise. It is necessary to encrypt (not only generate) random data because encrypted messages might have some common traits, which distinguish them from noise. E.g. in case of asymmetric encryption some bytes are allowed to have only certain values.
|
|
||||||
|
|
||||||
In some cases recipient might also be probabilistically identified if two nodes send each other messages with common traits, e.g. same Topic or same size. That's why it is important to use different Topics for sending and receiving the messages within the session.
|
|
||||||
|
|
||||||
### Topics
|
|
||||||
|
|
||||||
It is possible to send asymmetrically encrypted messages without any Topic. However, in case of huge traffic it might be not practical to try decrypting all the incoming messages, since decrypt operation is quite expensive. Some filtering might be necessary. Whisper allows to subscribe for messages with particular Topic or specify several possible Topics. It is also possible to subscribe for partial Topic(s), e.g. first one, two, or three bytes of the Topic.
|
|
||||||
|
|
||||||
Topic collisions are part of the plausible deniability strategy. Some messages from different nodes (and encrypted with different keys) should have the same Topic (or partial Topic). Therefore it is recommended to set the Topics dynamically, so that collisions will regulary occur on your node.
|
|
||||||
|
|
||||||
For example, if there are 6000 nodes in the network and each of them on average sends ten messages per minute, it would make sense to set only first byte of the Topic (leaving the other three bytes random). In this case each node will receive on average 1000 messages per second. The node will try to decrypt approximately four messages (those matching the Topic), and one of them will be successfully decrypted. The rest of the messages will be ignored and just forwarded to the other peers.
|
|
||||||
|
|
||||||
### Message Size and Padding
|
|
||||||
|
|
||||||
When sending the messages, another important metric which could potentially leak metainformation is the size. Therefore, depending on the circumstances, it might be useful to send messages only of certain size or always generate random size (not exceeding certain limit). The API allows easy setting of padding. The default implementation of Whisper also uses the padding to align the messages along the 256-byte boundaries.
|
|
||||||
|
|
||||||
### Symmetric vs. Asymmetric
|
|
||||||
|
|
||||||
In case of symmetric encryption, the nodes must have already exchanged the encryption key via some secure channel. So, they should use the same channel to exchange the Topics (or partial Topics), and maybe PoW requirement for individual messages. In case of asymmetric encryption, the public key is exchanged via open channels, and it might be impossible to exchange any other information before they engage in secure communication. In this case different strategies might be employed.
|
|
||||||
|
|
||||||
For example, the first message might be sent without any Topic. This message may contain all the information necessary to start a symmetrically encrypted session, complete with (partial) Topics, PoW requirement and symmetric keys. Because it requires trying to decrypt all the incoming asymmetric messages, the PoW requirement for such messages might be set very high, which might be acceptable since such messages are only sent once per session.
|
|
||||||
|
|
||||||
Alternatively, a partial Topic should be published along with the public key and PoW requirement. E.g., if we use two or three bytes for the partial Topic of symmetrically encrypted messages, we might only use one byte for the asymmetric encryption.
|
|
||||||
|
|
||||||
### Example of Session
|
|
||||||
|
|
||||||
Suppose two nodes want to engage in secure communication. One of them sends an asymmetrically encrypted message of certain (pre-defined) format, which contains two symmetric keys and corresponding partial Topics, all randomly generated. The sender of this message subscribes for the messages with the first Topic (encrypted with the first key), and always encrypts outgoing messages with the second key. The recipient subscribes for the messages with the second Topic (encrypted with the second key), and always encrypts outgoing messages with the first key. They also include the message number in each outgoing message, in order to ensure the correct order of the messages, and detect if some of them did not arrive. After the session is over, the keys are deleted and never used again.
|
|
||||||
|
|
||||||
In case of several participants (e.g. a group chat) they just need one additional key and one additional subscription for any additional participant.
|
|
||||||
|
|
||||||
### Plausible Deniability
|
|
||||||
|
|
||||||
Suppose a user has lost control of his key. It might happen due to hacker attack on his computer, or becuase a hostile entity forces him to reveal the key. In case he signed any message with his private key, it might be used as evidence against him. So, the user might prefer to use his key only to establish the session, and then engage in symmetrically encrypted communication without signing the messages. His peer may be sure about his identity, since the symmetric key was signed with his private key. But these messages can not be used as evidence, since this message could have been sent by anyone in possession of the symmetric key, especially if this key was used in a group chat session.
|
|
||||||
|
|
||||||
### Steganography
|
|
||||||
|
|
||||||
However, in some extreme cases even plausible deniability might not be enough. In those cases users might utilize the padding mechanism for steganographic purposes. It is possible to set arbitrary data as padding. The Whisper API allows easy access to padding for both writing and reading. Since vast majority of the messages will contain some kind of padding (either default or customized), it will be impossible to distinguish between randomly generated and encrypted padding bytes. The users should only use such encryption which does not reveal any metainformation (preferably symmetric stream ciphers), and then add the resulting data as padding to a message with some irrelevant payload.
|
|
||||||
|
|
||||||
### Private Networks
|
|
||||||
|
|
||||||
It is very easy to set up a private Whisper network, since Whisper does not contain any genesis block or indeed any state at all. You just start a bootstrap node to which everybody should connect. It might be useful for organizations with restricted access. Private network may have several advantages. For example, it might be very difficult for any adversary to join the network, which will make the traffic analysis almost impossible. Also, PoW requirement might be dropped, thus allowing instant messaging with very little overhead.
|
|
|
@ -1,64 +0,0 @@
|
||||||
---
|
|
||||||
title: Backup & restore
|
|
||||||
---
|
|
||||||
**DO NOT FORGET YOUR PASSWORD** and **BACKUP YOUR KEYSTORE**
|
|
||||||
|
|
||||||
# Backup & restore
|
|
||||||
|
|
||||||
## Data directory
|
|
||||||
|
|
||||||
Everything `geth` persists gets written inside its data directory (except for the PoW Ethash DAG, see note below).
|
|
||||||
The default data directory locations are platform specific:
|
|
||||||
|
|
||||||
* Mac: `~/Library/Ethereum`
|
|
||||||
* Linux: `~/.ethereum`
|
|
||||||
* Windows: `%APPDATA%\Ethereum`
|
|
||||||
|
|
||||||
Accounts are stored in the `keystore` subdirectory. The contents of this directories should be transportable between nodes, platforms, implementations (C++, Go, Python).
|
|
||||||
|
|
||||||
To configure the location of the data directory, the `--datadir` parameter can be specified. See [CLI Options](../interface/Command-Line-Options) for more details.
|
|
||||||
|
|
||||||
_**Note:** The [Ethash DAG](../how-to/Mining#ethash-dag) is stored at `~/.ethash` (Mac/Linux) or `%APPDATA%\Ethash` (Windows) so that it can be reused by all clients. You can store this in a different location by using a symbolic link._
|
|
||||||
|
|
||||||
## Upgrades
|
|
||||||
|
|
||||||
Sometimes the internal database formats need updating (for example, when upgrade from before 0.9.20). This can be run with the following command (geth should not be otherwise running):
|
|
||||||
|
|
||||||
```
|
|
||||||
geth upgradedb
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
|
|
||||||
Geth's blockchain and state databases can be removed with:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth removedb
|
|
||||||
```
|
|
||||||
|
|
||||||
This is useful for deleting an old chain and sync'ing to a new one. It only affects data directories that can be re-created on synchronisation and does not touch the keystore.
|
|
||||||
|
|
||||||
## Blockchain import/export
|
|
||||||
|
|
||||||
Export the blockchain in binary format with:
|
|
||||||
```
|
|
||||||
geth export <filename>
|
|
||||||
```
|
|
||||||
|
|
||||||
Or if you want to back up portions of the chain over time, a first and last block can be specified. For example, to back up the first epoch:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth export <filename> 0 29999
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that when backing up a partial chain, the file will be appended rather than truncated.
|
|
||||||
|
|
||||||
Import binary-format blockchain exports with:
|
|
||||||
```
|
|
||||||
geth import <filename>
|
|
||||||
```
|
|
||||||
|
|
||||||
_See https://github.com/ethereum/wiki/wiki/Blockchain-import-export for more info_
|
|
||||||
|
|
||||||
|
|
||||||
And finally: **DO NOT FORGET YOUR PASSWORD** and **BACKUP YOUR KEYSTORE**
|
|
|
@ -1,101 +0,0 @@
|
||||||
---
|
|
||||||
title: Code Review Guidelines
|
|
||||||
---
|
|
||||||
The only way to get code into go-ethereum is to send a pull request. 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][effgo]. Authors should avoid common
|
|
||||||
mistakes explained in the [Go Code Review Comments][revcomment] 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
|
|
||||||
|
|
||||||
As a reviewer, you may find yourself in one of the sitations below. Here's how to deal
|
|
||||||
with those:
|
|
||||||
|
|
||||||
* 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 your feedback: reviewers have authority to reject any change for technical reasons. If you're unsure, ask the team for a second opinion. You may close the PR if no consensus can be reached.
|
|
||||||
|
|
||||||
[effgo]: https://golang.org/doc/effective_go.html
|
|
||||||
[revcomment]: https://github.com/golang/go/wiki/CodeReviewComments
|
|
|
@ -1,153 +0,0 @@
|
||||||
---
|
|
||||||
title: Connecting to the network
|
|
||||||
---
|
|
||||||
## How Peers Are Found
|
|
||||||
|
|
||||||
Geth continuously attempts to connect to other nodes on the network
|
|
||||||
until it has peers. If you have UPnP enabled on your router or run
|
|
||||||
ethereum on an Internet-facing server, it will also accept connections
|
|
||||||
from other nodes.
|
|
||||||
|
|
||||||
Geth finds peers through something called the discovery protocol. In
|
|
||||||
the discovery protocol, nodes are gossipping with each other to find
|
|
||||||
out about other nodes on the network. In order to get going initially,
|
|
||||||
geth uses a set of bootstrap nodes whose endpoints are recorded in the
|
|
||||||
source code.
|
|
||||||
|
|
||||||
To change the bootnodes on startup, use the `--bootnodes` option and
|
|
||||||
separate the nodes by commas. For example:
|
|
||||||
|
|
||||||
geth --bootnodes enode://pubkey1@ip1:port1,enode://pubkey2@ip2:port2,enode://pubkey3@ip3:port3
|
|
||||||
|
|
||||||
## Common Problems With Connectivity
|
|
||||||
|
|
||||||
Sometimes you just can't get connected. The most common reasons are
|
|
||||||
as follows:
|
|
||||||
|
|
||||||
- Your local time might be incorrect. An accurate clock is required
|
|
||||||
to participate in the Ethereum network. Check your OS for how to resync
|
|
||||||
your clock (example sudo ntpdate -s time.nist.gov) because even 12
|
|
||||||
seconds too fast can lead to 0 peers.
|
|
||||||
- Some firewall configurations can prevent UDP traffic from flowing.
|
|
||||||
You can use the static nodes feature or `admin.addPeer()` on the console
|
|
||||||
to configure connections by hand.
|
|
||||||
|
|
||||||
To start geth without the discovery protocol, you can use the `--nodiscover` parameter. You only want this is you are running a test node or an experimental test network with fixed nodes.
|
|
||||||
|
|
||||||
## Checking Connectivity
|
|
||||||
|
|
||||||
To check how many peers the client is connected to in the interactive console, the `net` module has two attributes give you info about the number of peers and whether you are a listening node.
|
|
||||||
|
|
||||||
```js
|
|
||||||
> net.listening
|
|
||||||
true
|
|
||||||
> net.peerCount
|
|
||||||
4
|
|
||||||
```
|
|
||||||
|
|
||||||
To get more information about the connected peers, such as IP address and port number, supported protocols, use the `peers()` function of the `admin` object. `admin.peers()` returns the list of currently connected peers.
|
|
||||||
|
|
||||||
```
|
|
||||||
> admin.peers
|
|
||||||
[{
|
|
||||||
ID: 'a4de274d3a159e10c2c9a68c326511236381b84c9ec52e72ad732eb0b2b1a2277938f78593cdbe734e6002bf23114d434a085d260514ab336d4acdc312db671b',
|
|
||||||
Name: 'Geth/v0.9.14/linux/go1.4.2',
|
|
||||||
Caps: 'eth/60',
|
|
||||||
RemoteAddress: '5.9.150.40:30301',
|
|
||||||
LocalAddress: '192.168.0.28:39219'
|
|
||||||
}, {
|
|
||||||
ID: 'a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c',
|
|
||||||
Name: 'Geth/v0.9.15/linux/go1.4.2',
|
|
||||||
Caps: 'eth/60',
|
|
||||||
RemoteAddress: '52.16.188.185:30303',
|
|
||||||
LocalAddress: '192.168.0.28:50995'
|
|
||||||
}, {
|
|
||||||
ID: 'f6ba1f1d9241d48138136ccf5baa6c2c8b008435a1c2bd009ca52fb8edbbc991eba36376beaee9d45f16d5dcbf2ed0bc23006c505d57ffcf70921bd94aa7a172',
|
|
||||||
Name: 'pyethapp_dd52/v0.9.13/linux2/py2.7.9',
|
|
||||||
Caps: 'eth/60, p2p/3',
|
|
||||||
RemoteAddress: '144.76.62.101:30303',
|
|
||||||
LocalAddress: '192.168.0.28:40454'
|
|
||||||
}, {
|
|
||||||
ID: 'f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0',
|
|
||||||
Name: '++eth/Zeppelin/Rascal/v0.9.14/Release/Darwin/clang/int',
|
|
||||||
Caps: 'eth/60, shh/2',
|
|
||||||
RemoteAddress: '129.16.191.64:30303',
|
|
||||||
LocalAddress: '192.168.0.28:39705'
|
|
||||||
} ]
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
To check the ports used by geth and also find your enode URI run:
|
|
||||||
```
|
|
||||||
> admin.nodeInfo
|
|
||||||
{
|
|
||||||
Name: 'Geth/v0.9.14/darwin/go1.4.2',
|
|
||||||
NodeUrl: 'enode://3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694@[::]:30303',
|
|
||||||
NodeID: '3414c01c19aa75a34f2dbd2f8d0898dc79d6b219ad77f8155abf1a287ce2ba60f14998a3a98c0cf14915eabfdacf914a92b27a01769de18fa2d049dbf4c17694',
|
|
||||||
IP: '::',
|
|
||||||
DiscPort: 30303,
|
|
||||||
TCPPort: 30303,
|
|
||||||
Td: '2044952618444',
|
|
||||||
ListenAddr: '[::]:30303'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Custom Networks
|
|
||||||
|
|
||||||
Sometimes you might not need to connect to the live public network,
|
|
||||||
you can instead choose to create your own private testnet. This is
|
|
||||||
very useful if you don't need to test external contracts and want just
|
|
||||||
to test the technology, because you won't have to compete with other
|
|
||||||
miners and will easily generate a lot of test ether to play around
|
|
||||||
(replace 12345 with any non-negative number):
|
|
||||||
|
|
||||||
geth -—networkid="12345" console
|
|
||||||
|
|
||||||
It is also possible to run geth with a custom genesis block from a JSON file
|
|
||||||
by supplying the `--genesis` flag. The genesis JSON file should have the following
|
|
||||||
format:
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
"alloc": {
|
|
||||||
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {
|
|
||||||
"balance": "1606938044258990275541962092341162602522202993782792835301376"
|
|
||||||
},
|
|
||||||
"e6716f9544a56c530d868e4bfbacb172315bdead": {
|
|
||||||
"balance": "1606938044258990275541962092341162602522202993782792835301376"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
},
|
|
||||||
"nonce": "0x000000000000002a",
|
|
||||||
"difficulty": "0x020000",
|
|
||||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"coinbase": "0x0000000000000000000000000000000000000000",
|
|
||||||
"timestamp": "0x00",
|
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"extraData": "0x",
|
|
||||||
"gasLimit": "0x2fefd8"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Static nodes
|
|
||||||
|
|
||||||
Geth also supports a feature called static nodes if you have certain
|
|
||||||
peers you always want to connect to. Static nodes are re-connected
|
|
||||||
on disconnects. You can configure permanent static nodes by putting something like
|
|
||||||
the following into `<datadir>/geth/static-nodes.json`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
[
|
|
||||||
"enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303",
|
|
||||||
"enode://pubkey@ip:port"
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also add static nodes at runtime via the js console using [`admin.addPeer()`](../interface/JavaScript-Console#addpeer):
|
|
||||||
|
|
||||||
```js
|
|
||||||
admin.addPeer("enode://f4642fa65af50cfdea8fa7414a5def7bb7991478b768e296f5e4a54e8b995de102e0ceae2e826f293c481b5325f89be6d207b003382e18a8ecba66fbaf6416c0@33.4.2.1:30303")
|
|
||||||
```
|
|
||||||
|
|
||||||
Caveat: Currently the console is lacking support for removing a peer, increasing peercount or adding a non-static peer but not to keep try reconnecting.
|
|
|
@ -1,118 +0,0 @@
|
||||||
---
|
|
||||||
title: Creating your own Ethereum apps using Eth go
|
|
||||||
---
|
|
||||||
The modular nature of Go and the Ethereum Go implementation, [eth-go](https://github.com/ethereum/eth-go), make it very easy to build your own Ethereum native applications.
|
|
||||||
|
|
||||||
This post will cover the minimal steps required to build an native Ethereum application.
|
|
||||||
|
|
||||||
Ethereum comes with a global config found in the [ethutil](https://github.com/ethereum/eth-go/tree/master/ethutil) package. The global config requires you to set a base path to store it's files (database, settings, etc).
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
// Read config
|
|
||||||
ethutil.ReadConfig(".test", ethutil.LogStd, nil, "MyEthApp")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
ReadConfig takes four arguments. The data folder to use, a log flag, a globalConf instance and an id string to identify your app to other nodes in the network.
|
|
||||||
|
|
||||||
Once you've configured the global config you can set up and create your Ethereum node. The Ethereum Object, or Node, will handle all trafic from and to the Ethereum network as well as handle all incoming block and transactions. A new node can be created through the `new` method found in [eth-go](https://github.com/ethereum/eth-go).
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
// Read config
|
|
||||||
ethutil.ReadConfig(".test", ethutil.LogStd, nil, "MyEthApp")
|
|
||||||
|
|
||||||
// Create a new ethereum node
|
|
||||||
ethereum, err := eth.New(eth.CapDefault, false)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Could not start node: %s\n", err))
|
|
||||||
}
|
|
||||||
// Set the port (default 30303)
|
|
||||||
ethereum.Port = "10101"
|
|
||||||
// Once we reach max, bounce them off.
|
|
||||||
ethereum.MaxPeers = 10
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
New requires two arguments; the capabilities of the node and whether or not to use UPNP for port-forwarding. If you don't want to fallback to client-only features set an Ethereum port and the max amount of peers this node can connect to.
|
|
||||||
|
|
||||||
In order to identify the node to the network you'll be required to create a private key. The easiest way to create a new keypair is by using the `KeyRing` found in the `ethutil` package.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
// Read config
|
|
||||||
ethutil.ReadConfig(".test", ethutil.LogStd, nil, "MyEthApp")
|
|
||||||
|
|
||||||
// Create a new ethereum node
|
|
||||||
ethereum, err := eth.New(eth.CapDefault, false)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Could not start node: %s\n", err))
|
|
||||||
}
|
|
||||||
// Set the port (default 30303)
|
|
||||||
ethereum.Port = "10101"
|
|
||||||
// Once we reach max, bounce them off.
|
|
||||||
ethereum.MaxPeers = 10
|
|
||||||
|
|
||||||
keyRing := ethutil.GetKeyRing()
|
|
||||||
// Create a new key if non exist
|
|
||||||
if keyRing.Len() == 0 {
|
|
||||||
// Create a new keypair
|
|
||||||
keyPair, err := ethutil.GenerateNewKeyPair()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the keypair to the key ring
|
|
||||||
keyRing.Add(keyPair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the base Ethereum stack has been set up it's time to fire up its engines and connect to the main network.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ethereum/eth-go"
|
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Read config
|
|
||||||
ethutil.ReadConfig(".test", ethutil.LogStd, nil, "MyEthApp")
|
|
||||||
|
|
||||||
// Create a new ethereum node
|
|
||||||
ethereum, err := eth.New(eth.CapDefault, false)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Could not start node: %s\n", err))
|
|
||||||
}
|
|
||||||
// Set the port (default 30303)
|
|
||||||
ethereum.Port = "10101"
|
|
||||||
// Once we reach max, bounce them off.
|
|
||||||
ethereum.MaxPeers = 10
|
|
||||||
|
|
||||||
keyRing := ethutil.GetKeyRing()
|
|
||||||
// Create a new key if non exist
|
|
||||||
if keyRing.Len() == 0 {
|
|
||||||
// Create a new keypair
|
|
||||||
keyPair, err := ethutil.GenerateNewKeyPair()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the keypair to the key ring
|
|
||||||
keyRing.Add(keyPair)
|
|
||||||
}
|
|
||||||
|
|
||||||
ethereum.Start(true)
|
|
||||||
ethereum.WaitForShutdown()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`ethereum.Start()` takes one argument, whether or not we want to connect to one of the known seed nodes. If you want your own little testnet-in-a-box you can disable it else set it to true.
|
|
||||||
|
|
||||||
Your node should now be catching up with the blockchain. From here on out you are on your own. You could create a reactor to listen to specific events or just dive into the chain state directly. If you want to look at some example code you can check [DNSEth here.](https://github.com/maran/dnseth)
|
|
||||||
|
|
||||||
Have fun!
|
|
|
@ -1,167 +0,0 @@
|
||||||
---
|
|
||||||
title: Cross-compiling Ethereum
|
|
||||||
---
|
|
||||||
**Note: All of these and much more have been merged into the project Makefile.
|
|
||||||
You can cross build via `make geth-<os>-<platform>` without needing to know any
|
|
||||||
of these details from below.**
|
|
||||||
|
|
||||||
Developers usually have a preferred platform that they feel most comfortable
|
|
||||||
working in, with all the necessary tools, libraries and environments set up for
|
|
||||||
an optimal workflow. However, there's often need to build for either a different
|
|
||||||
CPU architecture, or an entirely different operating system; but maintaining a
|
|
||||||
development environment for each and switching between the them quickly becomes
|
|
||||||
unwieldy.
|
|
||||||
|
|
||||||
Here we present a very simple way to cross compile Ethereum to various operating
|
|
||||||
systems and architectures using a minimal set of prerequisites and a completely
|
|
||||||
containerized approach, guaranteeing that your development environment remains
|
|
||||||
clean even after the complex requirements and mechanisms of a cross compilation.
|
|
||||||
|
|
||||||
The currently supported target platforms are:
|
|
||||||
|
|
||||||
- ARMv7 Android and iOS
|
|
||||||
- 32 bit, 64 bit and ARMv5 Linux
|
|
||||||
- 32 bit and 64 bit Mac OSX
|
|
||||||
- 32 bit and 64 bit Windows
|
|
||||||
|
|
||||||
Please note, that cross compilation does not replace a release build. Although
|
|
||||||
resulting binaries can usually run perfectly on the desired platform, compiling
|
|
||||||
on a native system with the specialized tools provided by the official vendor
|
|
||||||
can often result in more a finely optimized code.
|
|
||||||
|
|
||||||
## Cross compilation environment
|
|
||||||
|
|
||||||
Although the `go-ethereum` project is written in Go, it does include a bit of C
|
|
||||||
code shared between all implementations to ensure that all perform equally well,
|
|
||||||
including a dependency to the GNU Multiple Precision Arithmetic Library. Because
|
|
||||||
of these, Go cannot by itself compile to a different platform than the host. To
|
|
||||||
overcome this limitation, we will use [`xgo`](https://github.com/karalabe/xgo),
|
|
||||||
a Go cross compiler package based on Docker containers that has been architected
|
|
||||||
specifically to allow both embedded C snippets as well as simpler external C
|
|
||||||
dependencies during compilation.
|
|
||||||
|
|
||||||
The `xgo` project has two simple dependencies: Docker (to ensure that the build
|
|
||||||
environment is completely contained) and Go. On most platforms these should be
|
|
||||||
available from the official package repositories. For manually installing them,
|
|
||||||
please consult their install guides at [Docker](https://docs.docker.com/installation/)
|
|
||||||
and [Go](https://golang.org/doc/install) respectively. This guide assumes that these
|
|
||||||
two dependencies are met.
|
|
||||||
|
|
||||||
To install and/or update xgo, simply type:
|
|
||||||
|
|
||||||
$ go get -u github.com/karalabe/xgo
|
|
||||||
|
|
||||||
You can test whether `xgo` is functioning correctly by requesting it to cross
|
|
||||||
compile itself and verifying that all cross compilations succeeded or not.
|
|
||||||
|
|
||||||
$ xgo github.com/karalabe/xgo
|
|
||||||
...
|
|
||||||
|
|
||||||
$ ls -al
|
|
||||||
-rwxr-xr-x 1 root root 2792436 Sep 14 16:45 xgo-android-21-arm
|
|
||||||
-rwxr-xr-x 1 root root 2353212 Sep 14 16:45 xgo-darwin-386
|
|
||||||
-rwxr-xr-x 1 root root 2906128 Sep 14 16:45 xgo-darwin-amd64
|
|
||||||
-rwxr-xr-x 1 root root 2388288 Sep 14 16:45 xgo-linux-386
|
|
||||||
-rwxr-xr-x 1 root root 2960560 Sep 14 16:45 xgo-linux-amd64
|
|
||||||
-rwxr-xr-x 1 root root 2437864 Sep 14 16:45 xgo-linux-arm
|
|
||||||
-rwxr-xr-x 1 root root 2551808 Sep 14 16:45 xgo-windows-386.exe
|
|
||||||
-rwxr-xr-x 1 root root 3130368 Sep 14 16:45 xgo-windows-amd64.exe
|
|
||||||
|
|
||||||
|
|
||||||
## Building Ethereum
|
|
||||||
|
|
||||||
Cross compiling Ethereum is analogous to the above example, but an additional
|
|
||||||
flags is required to satisfy the dependencies:
|
|
||||||
|
|
||||||
- `--deps` is used to inject arbitrary C dependency packages and pre-build them
|
|
||||||
|
|
||||||
Injecting the GNU Arithmetic Library dependency and selecting `geth` would be:
|
|
||||||
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
...
|
|
||||||
|
|
||||||
$ ls -al
|
|
||||||
-rwxr-xr-x 1 root root 23213372 Sep 14 17:59 geth-android-21-arm
|
|
||||||
-rwxr-xr-x 1 root root 14373980 Sep 14 17:59 geth-darwin-386
|
|
||||||
-rwxr-xr-x 1 root root 17373676 Sep 14 17:59 geth-darwin-amd64
|
|
||||||
-rwxr-xr-x 1 root root 21098910 Sep 14 17:59 geth-linux-386
|
|
||||||
-rwxr-xr-x 1 root root 25049693 Sep 14 17:59 geth-linux-amd64
|
|
||||||
-rwxr-xr-x 1 root root 20578535 Sep 14 17:59 geth-linux-arm
|
|
||||||
-rwxr-xr-x 1 root root 16351260 Sep 14 17:59 geth-windows-386.exe
|
|
||||||
-rwxr-xr-x 1 root root 19418071 Sep 14 17:59 geth-windows-amd64.exe
|
|
||||||
|
|
||||||
|
|
||||||
As the cross compiler needs to build all the dependencies as well as the main
|
|
||||||
project itself for each platform, it may take a while for the build to complete
|
|
||||||
(approximately 3-4 minutes on a Core i7 3770K machine).
|
|
||||||
|
|
||||||
### Fine tuning the build
|
|
||||||
|
|
||||||
By default Go, and inherently `xgo`, checks out and tries to build the master
|
|
||||||
branch of a source repository. However, more often than not, you'll probably
|
|
||||||
want to build a different branch from possibly an entirely different remote
|
|
||||||
repository. These can be controlled via the `--remote` and `--branch` flags.
|
|
||||||
|
|
||||||
To build the `develop` branch of the official `go-ethereum` repository instead
|
|
||||||
of the default `master` branch, you just need to specify it as an additional
|
|
||||||
command line flag (`--branch`):
|
|
||||||
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
--branch=develop \
|
|
||||||
github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
|
|
||||||
Additionally, during development you will most probably want to not only build
|
|
||||||
a custom branch, but also one originating from your own fork of the repository
|
|
||||||
instead of the upstream one. This can be done via the `--remote` flag:
|
|
||||||
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
--remote=https://github.com/karalabe/go-ethereum \
|
|
||||||
--branch=rpi-staging \
|
|
||||||
github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
|
|
||||||
By default `xgo` builds binaries for all supported platforms and architectures,
|
|
||||||
with Android binaries defaulting to the highest released Android NDK platform.
|
|
||||||
To limit the build targets or compile to a different Android platform, use the
|
|
||||||
`--targets` CLI parameter.
|
|
||||||
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
--targets=android-16/arm,windows/* \
|
|
||||||
github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
|
|
||||||
### Building locally
|
|
||||||
|
|
||||||
If you would like to cross compile your local development version, simply specify
|
|
||||||
a local path (starting with `.` or `/`), and `xgo` will use all local code from
|
|
||||||
`GOPATH`, only downloading missing dependencies. In such a case of course, the
|
|
||||||
`--branch`, `--remote` and `--pkg` arguments are no-op:
|
|
||||||
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
./cmd/geth
|
|
||||||
|
|
||||||
## Using the Makefile
|
|
||||||
|
|
||||||
Having understood the gist of `xgo` based cross compilation, you do not need to
|
|
||||||
actually memorize and maintain these commands, as they have been incorporated into
|
|
||||||
the official [Makefile](https://github.com/ethereum/go-ethereum/blob/master/Makefile)
|
|
||||||
and can be invoked with a trivial `make` request:
|
|
||||||
|
|
||||||
* `make geth-cross`: Cross compiles to every supported OS and architecture
|
|
||||||
* `make geth-<os>`: Cross compiles supported architectures of a particular OS (e.g. `linux`)
|
|
||||||
* `make geth-<os>-<arch>`: Cross compiles to a specific OS/architecture (e.g. `linux`, `arm`)
|
|
||||||
|
|
||||||
We advise using the `make` based commands opposed to manually invoking `xgo` as we do
|
|
||||||
maintain the Makefile actively whereas we cannot guarantee that this document will be
|
|
||||||
always readily updated to latest advancements.
|
|
||||||
|
|
||||||
### Tuning the cross builds
|
|
||||||
|
|
||||||
A few of the `xgo` build options have also been surfaced directly into the Makefile to
|
|
||||||
allow fine tuning builds to work around either upstream Go issues, or to enable some
|
|
||||||
fancier mechanics.
|
|
||||||
|
|
||||||
- `make ... GO=<go>`: Use a specific Go runtime (e.g. `1.5.1`, `1.5-develop`, `develop`)
|
|
||||||
- `make ... MODE=<mode>`: Build a specific target type (e.g. `exe`, `c-archive`).
|
|
||||||
|
|
||||||
Please note that these are not yet fully finalized, so they may or may not change in
|
|
||||||
the future as our code and the Go runtime features change.
|
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
title: Developer guide
|
|
||||||
---
|
|
||||||
### Native DApps
|
|
||||||
|
|
||||||
[Introduction and packages](Native:-Introduction)
|
|
||||||
|
|
||||||
[Account management](Native:-Account-management)
|
|
||||||
|
|
||||||
### Mobile platforms
|
|
||||||
|
|
||||||
[Introduction and packages](Mobile:-Introduction)
|
|
||||||
|
|
||||||
[Account management](Mobile:-Account-management)
|
|
||||||
|
|
||||||
### Transaction tracing
|
|
||||||
|
|
||||||
[Introduction and basics](Tracing:-Introduction)
|
|
||||||
|
|
||||||
[Custom in-node tracers](Tracing:-Custom-tracers)
|
|
||||||
|
|
||||||
[Full blockchain tracing](Tracing:-Blockchain-tracing)
|
|
||||||
|
|
||||||
[Dependency exfiltration](Tracing:-Exfiltration)
|
|
|
@ -1,242 +0,0 @@
|
||||||
---
|
|
||||||
title: Diagnostic tool wnode
|
|
||||||
---
|
|
||||||
## Wnode
|
|
||||||
|
|
||||||
Wnode (whisper node) is a command-line diagnostic tool. It does not have a nice user interface, because its main purpose is diagnostic, and it's meant to be very light-weight rather than beautiful. Wnode might be used for different purposes, including:
|
|
||||||
|
|
||||||
- running a standalone bootstrap node, in order to set up a private whisper network
|
|
||||||
- connecting to particular node for debugging or other purposes
|
|
||||||
- engaging in command-line chat with another peer in order to test its functionality
|
|
||||||
- sending and receiving text messages
|
|
||||||
- sending and receiving files
|
|
||||||
- running fully functional mail server
|
|
||||||
- testing functionality of mail client
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
> wnode [flags/arguments]
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
> wnode -forwarder -standalone -ip=127.0.0.1:30381 -idfile=config.txt -mailserver -dbpath=tmp/db
|
|
||||||
|
|
||||||
#### Flags
|
|
||||||
|
|
||||||
-asym: use asymmetric encryption in the chat
|
|
||||||
|
|
||||||
-fileexchange: file exchange mode (send and receive files instead of text messages)
|
|
||||||
|
|
||||||
-forwarder: forwarder mode (only forward; neither send nor decrypt messages)
|
|
||||||
|
|
||||||
-mailserver: mail server mode (delivers expired messages on demand)
|
|
||||||
|
|
||||||
-mailclient: request expired messages from the mail server
|
|
||||||
|
|
||||||
-standalone: don't actively connect to any peers, wait for incoming connections instead
|
|
||||||
|
|
||||||
-test: use of predefined parameters for diagnostics, including passwords
|
|
||||||
|
|
||||||
-generatekey: generate a new private key (ECIES) and exit
|
|
||||||
|
|
||||||
#### Arguments
|
|
||||||
|
|
||||||
In case of missing arguments wnode will either use default value or ask you to provide them. For security reasons, you can not provide passwords in command-line arguments. Only in test mode hardcoded passwords are used.
|
|
||||||
|
|
||||||
-verbosity:
|
|
||||||
Verbosity level of logging. Int value between 0 and 5. Default value 1. For example: -verbosity=5.
|
|
||||||
|
|
||||||
-ttl:
|
|
||||||
Time-to-live for messages in seconds. Default value 30. For example: -ttl=20.
|
|
||||||
|
|
||||||
-maxsize:
|
|
||||||
Maximum allowed message size in bytes.
|
|
||||||
|
|
||||||
-work:
|
|
||||||
Maximum time in seconds allowed to spend on proof of work in order to achieve the target (set by 'pow' argument).
|
|
||||||
|
|
||||||
-pow:
|
|
||||||
PoW target for normal messages in float format (e.g. -pow=2.7).
|
|
||||||
|
|
||||||
-mspow:
|
|
||||||
PoW requirement for Mail Server request.
|
|
||||||
|
|
||||||
-ip:
|
|
||||||
IP address and port of this node (e.g. 127.0.0.1:30303).
|
|
||||||
|
|
||||||
-pub:
|
|
||||||
Public key of your peer (for asymmetric encryption). For example:
|
|
||||||
-pub=0x07af49cbe6353b8732a8b9eb20dd1472f3d4512cd1a11382ee2817cc6de9453bc07c32c730b93bc83877b11e4f47d718751297f4edcbf35015df2b34ff5fc6a75d
|
|
||||||
|
|
||||||
-idfile:
|
|
||||||
File name containing node ID (private key) in hexadecimal string format.
|
|
||||||
For example: -idfile=/home/vlad/tmp/config
|
|
||||||
Example of the file content: b3651aff593ef395ee7c16f3ca681830f7d8d0b2729cf472b14f2c4ebe833aa0
|
|
||||||
|
|
||||||
-boot:
|
|
||||||
The bootstrap node you want to connect to. For example:
|
|
||||||
-boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379
|
|
||||||
|
|
||||||
-topic:
|
|
||||||
Message topic in hexadecimal format. For example: -topic=70a4beef.
|
|
||||||
|
|
||||||
-dbpath:
|
|
||||||
Path to directory where Mail Server will store the incoming messages.
|
|
||||||
For example: -dbpath=tmp/myfiles/archive
|
|
||||||
|
|
||||||
-savedir:
|
|
||||||
Directory where successfully decrypted incoming messages will be saved as files in plain format.
|
|
||||||
Message hashes will be used as file names in order to avoid collisions.
|
|
||||||
By default, only big messages are stored there.
|
|
||||||
In 'fileexchange' mode all messages are stored there.
|
|
||||||
|
|
||||||
### Scenarios & Examples
|
|
||||||
|
|
||||||
For simplicity, in these examples we assume that we only use wnode to communicate with another wnode.
|
|
||||||
|
|
||||||
#### Start a bootstrap node for test network
|
|
||||||
|
|
||||||
> wnode -standalone -forwarder -ip=127.0.0.1:30379
|
|
||||||
|
|
||||||
result output:
|
|
||||||
|
|
||||||
my public key: 0x040ef7acd60781c336c52056b3782f7eae45be2063e591ac6b78472dc27ba770010bde445ffd2f3623ad656f3859e00d11ef518df4916c4d4e258c60b15f34c682 enode://15454fc65bbf0031155f4eee83fa732f1454c314e9f78ade9cba4d4a098d29edbf5431764ee65b200169025c3f900cacc3348a000dda7a8a0d9643d0b7618712@127.0.0.1:30379
|
|
||||||
Bootstrap Whisper node started
|
|
||||||
|
|
||||||
After the bootstrap node has started, another local node can connect to it, using the resulting enode:
|
|
||||||
|
|
||||||
> wnode -test -boot=enode://15454fc65bbf0031155f4eee83fa732f1454c314e9f78ade9cba4d4a098d29edbf5431764ee65b200169025c3f900cacc3348a000dda7a8a0d9643d0b7618712@127.0.0.1:30379
|
|
||||||
|
|
||||||
result output:
|
|
||||||
|
|
||||||
............................
|
|
||||||
Whisper node started
|
|
||||||
Connected to peer.
|
|
||||||
............................
|
|
||||||
|
|
||||||
Now, if you restart you bootstrap node, its enode will be different, because new ID will be randomly generated. If you need to repeat the tests multiple times, it will be extremely boring to copy and paste new enode every time you restart. Instead, you can load ID from file using 'idfile' argument.
|
|
||||||
|
|
||||||
Generating ID:
|
|
||||||
|
|
||||||
> wnode -generatekey
|
|
||||||
|
|
||||||
result:
|
|
||||||
|
|
||||||
c74ea2702eb32f523acb118649998e1c8b5690cf0a14bffda7e87b411db3499a
|
|
||||||
|
|
||||||
Then save it to file:
|
|
||||||
|
|
||||||
> echo c74ea2702eb32f523acb118649998e1c8b5690cf0a14bffda7e87b411db3499a > pk1.txt
|
|
||||||
|
|
||||||
Then start the bootstrap node with persistent ID:
|
|
||||||
|
|
||||||
> wnode -forwarder -standalone -ip=127.0.0.1:30379 -idfile=pk1.txt
|
|
||||||
|
|
||||||
result:
|
|
||||||
|
|
||||||
my public key: 0x04be81a00a90f5c21ead8887eaa254b3f7a37e06f8f2d776dcc46954a228bc50c6fb6dfd155f7e44e6fef9b62fdf6dad041759b864d2cbe4089b6f5c16a817ff46 enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379
|
|
||||||
Filter is configured for the topic: 5a4ea131
|
|
||||||
Bootstrap Whisper node started
|
|
||||||
|
|
||||||
Now you can always use the same command to connect to your bootstrap node:
|
|
||||||
|
|
||||||
> wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379
|
|
||||||
|
|
||||||
Please note that ID file is stored unencrypted. It should be used only for test purposes.
|
|
||||||
|
|
||||||
Of course, two local whisper nodes are only useful for the most basic tests.
|
|
||||||
In order to set up a bootstrap node on a server with dedicated IP address, you need to specify its IP explicitly:
|
|
||||||
|
|
||||||
> wnode -forwarder -standalone -ip=52.178.211.103:30379
|
|
||||||
|
|
||||||
#### Chat
|
|
||||||
|
|
||||||
Now we will start a chat between two or more nodes sharing the same password, using symmetric encryption. One of the nodes should be started with 'standalone' flag, and another must connect to the first one. It is easy to do on the same machine or on a dedicated server. But what if two peers are behind distinct NAT? In that case, you need a third bootstrap node on a dedicated server, which both peers can connect to. At the time of writing we have out test node with the following enode:
|
|
||||||
enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379,
|
|
||||||
to which both peers can connect with the following command:
|
|
||||||
|
|
||||||
> wnode -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379
|
|
||||||
|
|
||||||
Then you will be prompted to enter the password for symmetric encryption. From this password symmetric key will be derived. The topic will be derived from the password as well, unless you provide your own (which is strongly encouraged for any meaningful communication):
|
|
||||||
|
|
||||||
> wnode -topic=a6fcb30d -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379
|
|
||||||
|
|
||||||
Now you can type text messages:
|
|
||||||
|
|
||||||
hello world!
|
|
||||||
|
|
||||||
1493061848 <031792461900245c6919c4b23447ef8ba43f79a2>: hello world!
|
|
||||||
|
|
||||||
You will see your own message successfully decrypted and printed on the screen. The first number (1493061848) is UNIX time in seconds. This format is useful for Mail Client/Server tests. The number in brackets is ID with which the message is signed. In this case -- your own ID. If you see only zeros there, it means the message is not signed, although encrypted with the right key. Another wnode peer will show the same output:
|
|
||||||
|
|
||||||
1493061848 [031792461900245c6919c4b23447ef8ba43f79a2]: hello world!
|
|
||||||
|
|
||||||
Almost the same, only the brackets are different, indicating that this is not its own message -- originated from somebody else.
|
|
||||||
|
|
||||||
#### Chat with Asymmetric Encryption
|
|
||||||
|
|
||||||
Connect both peers to the same bootstrap node again, but this time with 'asym' flag:
|
|
||||||
|
|
||||||
> wnode -topic=a6fcb30d -asym -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379
|
|
||||||
|
|
||||||
result:
|
|
||||||
|
|
||||||
my public key: 0x0405007821171295a716c9d091371e836e98a5206d5b9ce9177df90c83fc308ebae2786a9c7bff999ad83d12be08e597d4b5a5240f3bb0bc366f008b7d0908df8a
|
|
||||||
enode://efe233263c78482111ba6c058ccc69b7a2ea3372774733def4fd5a357dfbaa67657e665078d573f11876fd2b7d75d41926976f41e257f91b486e9d36f4143c8a@[::]:42562
|
|
||||||
Whisper node started
|
|
||||||
Connected to peer.
|
|
||||||
Please enter the peer's public key:
|
|
||||||
|
|
||||||
First line of the output contains the key which should be passed to anther peer, and vice versa. Then you can proceed with the chat as in the previous case.
|
|
||||||
|
|
||||||
#### Sending and receiving files
|
|
||||||
|
|
||||||
Start wnode with 'fileexchange' flag, and 'test' flag for simplicity. Suppose we want to store the incoming messages in the directory /home/tester/tmp/msg. In that case:
|
|
||||||
|
|
||||||
> wnode -standalone -ip=127.0.0.1:30379 -idfile=pk1.txt -fileexchange -savedir=/home/tester/tmp/msg
|
|
||||||
|
|
||||||
Now, start another wnode and connect to the first one:
|
|
||||||
|
|
||||||
> wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379
|
|
||||||
|
|
||||||
After you will type and send messages from the second node, you will see the first one to display something like this:
|
|
||||||
|
|
||||||
1493124416 {624fdf6983940c7ffa8a4742f76dc78ae9775c47}: message received and saved as 'aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d' (4 bytes)
|
|
||||||
|
|
||||||
As you see, messages are not displayed, but saved instead. Now you can open the file /home/tester/tmp/msg/aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d and examine its contents.
|
|
||||||
|
|
||||||
If you want to send a file from the 'fileexchange' peer, just type the file name. For example:
|
|
||||||
|
|
||||||
> /home/tester/tmp/msg/aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d
|
|
||||||
|
|
||||||
Another peer should receive the message, decrypt and display it on the screen.
|
|
||||||
If you want to use your own password instead of hardcoded one, just call wnode without 'test' flag.
|
|
||||||
Of course, you can also switch to asymmetric encryption by providing 'asym' flag.
|
|
||||||
|
|
||||||
#### Mail Server & Client
|
|
||||||
|
|
||||||
Whisper protocol allows you to exchange messages with other peers only if you are online. But what if you go offline? Will important messages be lost forever? The golang implementation of Whisper v5 has a built-in support for Mail Client/Server functionality, which allows to create very secure (and even dark) anonymous email-like system. Wnode is designed to demonstrate the viability of such project.
|
|
||||||
|
|
||||||
Mail Server and Client must have direct connection, since they exchange special kind of messages, which are not propagated any further. The reason for that is simple: if you receive the old (expired) message from the Server, and try to send it to other peers, they will recognise the message as expired, and drop connection with you.
|
|
||||||
|
|
||||||
Starting Mail Server:
|
|
||||||
|
|
||||||
> wnode -mailserver -forwarder -standalone -test -ip=127.0.0.1:30381 -idfile=pk1.txt -dbpath=/home/tester/tmp/arj
|
|
||||||
|
|
||||||
Now start another node, connect to the Server, and send some test messages to fill the database:
|
|
||||||
|
|
||||||
> wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30381
|
|
||||||
|
|
||||||
Note the UNIX time of the messages. For example: 1493127055.
|
|
||||||
Now start the Mail Client and connect to the Server:
|
|
||||||
|
|
||||||
> wnode -mailclient -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30381
|
|
||||||
|
|
||||||
You will be prompted to enter the time range of the archived messages you want to receive:
|
|
||||||
|
|
||||||
> Please enter the lower limit of the time range (unix timestamp): 1493127000
|
|
||||||
> Please enter the upper limit of the time range (unix timestamp): 1493127099
|
|
||||||
> Please enter the topic (hexadecimal):
|
|
||||||
|
|
||||||
You can leave the topic empty for now, in which case all the messages will be delivered, regardless of the topic.
|
|
||||||
The message should be delivered by the the Server, decrypted by the Client and displayed on the screen.
|
|
|
@ -1,86 +0,0 @@
|
||||||
---
|
|
||||||
title: Disclaimer
|
|
||||||
---
|
|
||||||
|
|
||||||
Safety caveats
|
|
||||||
|
|
||||||
## Security warnings
|
|
||||||
|
|
||||||
* **You are responsible for your own computer security.** If your machine is compromised you **will** lose your ether, access to any contracts and maybe more.
|
|
||||||
|
|
||||||
* **You are responsible for your own actions.** If you mess something up or break any laws while using this software, it's your fault, and your fault only.
|
|
||||||
|
|
||||||
* **You are responsible for your own karma.** Don't be a jerk and respect others.
|
|
||||||
|
|
||||||
* This software is open source under a [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl-3.0.en.html) license.
|
|
||||||
|
|
||||||
## Legal warning: Disclaimer of Liabilites and Warranties
|
|
||||||
|
|
||||||
### Short version
|
|
||||||
|
|
||||||
* **The user expressly knows and agrees that the user is using the ethereum platform at the user’s sole risk.**
|
|
||||||
* **The user represents that the user has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software, eth platform and eth.**
|
|
||||||
* **The user acknowledges and agrees that, to the fullest extent permitted by any applicable law, the disclaimers of liability contained herein apply to any and all damages or injury whatsoever caused by or related to risks of, use of, or inability to use, eth or the ethereum platform under any cause or action whatsoever of any kind in any jurisdiction, including, without limitation, actions for breach of warranty, breach of contract or tort (including negligence) and that neither stiftung ethereum nor the ethereum team shall be liable for any indirect, incidental, special, exemplary or consequential damages, including for loss of profits, goodwill or data.**
|
|
||||||
* **Some jurisdictions do not allow the exclusion of certain warranties or the limitation or exclusion of liability for certain types of damages. therefore, some of the above limitations in this section may not apply to a user. In particular, nothing in these terms shall affect the statutory rights of any user or exclude injury arising from any willful misconduct or fraud of stiftung ethereum.**
|
|
||||||
|
|
||||||
### Long Version: Terms and Conditions
|
|
||||||
|
|
||||||
The following Terms and Conditions (“Terms”) govern the use of the Ethereum open source software platform (“Ethereum Platform”). Prior to any use of the Ethereum Platform, the User confirms to understand and expressly agrees to all of the Terms. All capitalized terms in this agreement will be given the same effect and meaning as in the Terms. The group of developers and other personnel that is now, or will be, employed by, or contracted with, Stiftung Ethereum (“Stiftung Ethereum”) is termed the “Ethereum Team.” The Platform will be developed by persons and entities who support Ethereum, including both volunteers and developers who are paid by nonprofit entities interested in supporting the Ethereum Platform.
|
|
||||||
|
|
||||||
The user acknowledges the following serious risks to any use the Ethereum Platform and ETH and expressly agrees not to hold liable Ethereum Stiftung or Ethereum Team should any of these risks occur:
|
|
||||||
|
|
||||||
#### Risk of Regulatory Actions in One or More Jurisdictions
|
|
||||||
|
|
||||||
The Ethereum Platform and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of Stiftung Ethereum to continue to develop the Ethereum Platform, or which could impeded or limit the ability of User to use Ethereum Platform or ETH.
|
|
||||||
|
|
||||||
#### Risk of Alternative, Unofficial Ethereum Networks
|
|
||||||
|
|
||||||
It is possible that alternative Ethereum-based networks could be established, which utilize the same open source source code and open source protocol underlying the Ethereum Platform. The Ethereum network may compete with these alternative Ethereum-based networks, which could potentially negatively impact the Ethereum Platform and ETH.
|
|
||||||
|
|
||||||
#### Risk of Insufficient Interest in the Ethereum Platform or Distributed Applications
|
|
||||||
|
|
||||||
It is possible that the Ethereum Platform will not be used by a large number of external businesses, individuals, and other organizations and that there will be limited public interest in the creation and development of distributed applications. Such a lack of interest could impact the development of the Ethereum Platform and potential uses of ETH. It cannot predict the success of its own development efforts or the efforts of other third parties.
|
|
||||||
|
|
||||||
#### Risk that the Ethereum Platform, As Developed, Will Not Meet the Expectations of User
|
|
||||||
|
|
||||||
The User recognizes that the Ethereum Platform is under development and may undergo significant changes before release. User acknowledges that any expectations regarding the form and functionality of the Ethereum Platform held by the User may not be met upon release of the Ethereum Platform, for any number of reasons including a change in the design and implementation plans and execution of the implementation of the Ethereum Platform.
|
|
||||||
|
|
||||||
#### Risk of Security Weaknesses in the Ethereum Platform Core Infrastructure Software
|
|
||||||
|
|
||||||
The Ethereum Platform rests on open-source software, and there is a risk that the Ethereum Stiftung or the Ethereum Team, or other third parties not directly affiliated with the Stiftung Ethereum, may introduce weaknesses or bugs into the core infrastructural elements of the Ethereum Platform causing the system to lose ETH stored in one or more User accounts or other accounts or lose sums of other valued tokens issued on the Ethereum Platform.
|
|
||||||
|
|
||||||
#### Risk of Weaknesses or Exploitable Breakthroughs in the Field of Cryptography
|
|
||||||
|
|
||||||
Cryptography is an art, not a science. And the state of the art can advance over time Advances in code cracking, or technical advances such as the development of quantum computers, could present risks to cryptocurrencies and the Ethereum Platform, which could result in the theft or loss of ETH. To the extent possible, Stiftung Ethereum intends to update the protocol underlying the Ethereum Platform to account for any advances in cryptography and to incorporate additional security measures, but cannot it cannot predict the future of cryptography or the success of any future security updates.
|
|
||||||
|
|
||||||
#### Risk of Ether Mining Attacks
|
|
||||||
|
|
||||||
As with other cryptocurrencies, the blockchain used for the Ethereum Platform is susceptible to mining attacks, including but not limited to double-spend attacks, majority mining power attacks, “selfish-mining” attacks, and race condition attacks. Any successful attacks present a risk to the Ethereum Platform, expected proper execution and sequencing of ETH transactions, and expected proper execution and sequencing of contract computations. Despite the efforts of the Ethereum Stiftung and Team, known or novel mining attacks may be successful.
|
|
||||||
|
|
||||||
#### Risk of Rapid Adoption and Increased Demand
|
|
||||||
|
|
||||||
If the Ethereum Platform is rapidly adopted, the demand for ETH could rise dramatically and at a pace that exceeds the rate with which ETH miners can create new ETH tokens. Under such a scenario, the entire Ethereum Platform could become destabilized, due to the increased cost of running distributed applications. In turn, this could dampen interest in the Ethereum Platform and ETH. Instability in the demand of for ETH may lead to a negative change of the economical parameters of an Ethereum based business which could result in the business being unable to continue to operate economically or to cease operation.
|
|
||||||
|
|
||||||
#### Risk of Rapid Adoption and Insufficiency of Computational Application Processing Power on the Ethereum Platform
|
|
||||||
|
|
||||||
If the Ethereum Platform is rapidly adopted, the demand for transaction processing and distributed application computations could rise dramatically and at a pace that exceeds the rate with which ETH miners can bring online additional mining power. Under such a scenario, the entire Ethereum Platform could become destabilized, due to the increased cost of running distributed applications. In turn, this could dampen interest in the Ethereum Platform and ETH. Insufficiency of computational resources and an associated rise in the price of ETH could result in businesses being unable to acquire scarce computational resources to run their distributed applications. This would represent revenue losses to businesses or worst case, cause businesses to cease operations because such operations have become uneconomical due to distortions in the crypto-economy.
|
|
||||||
|
|
||||||
Acknowledgment, Acceptance of all Risks and Disclaimer of Warranties and Liabilities
|
|
||||||
**THE USER EXPRESSLY KNOWS AND AGREES THAT THE USER IS USING THE ETHEREUM PLATFORM AT THE USER’S SOLE RISK. THE USER REPRESENTS THAT THE USER HAS AN ADEQUATE UNDERSTANDING OF THE RISKS, USAGE AND INTRICACIES OF CRYPTOGRAPHIC TOKENS AND BLOCKCHAIN-BASED OPEN SOURCE SOFTWARE, ETH PLATFORM AND ETH. THE USER ACKNOWLEDGES AND AGREES THAT, TO THE FULLEST EXTENT PERMITTED BY ANY APPLICABLE LAW, THE DISCLAIMERS OF LIABILITY CONTAINED HEREIN APPLY TO ANY AND ALL DAMAGES OR INJURY WHATSOEVER CAUSED BY OR RELATED TO RISKS OF, USE OF, OR INABILITY TO USE, ETH OR THE ETHEREUM PLATFORM UNDER ANY CAUSE OR ACTION WHATSOEVER OF ANY KIND IN ANY JURISDICTION, INCLUDING, WITHOUT LIMITATION, ACTIONS FOR BREACH OF WARRANTY, BREACH OF CONTRACT OR TORT (INCLUDING NEGLIGENCE) AND THAT NEITHER STIFTUNG ETHEREUM NOR ETHERUM TEAM SHALL BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, INCLUDING FOR LOSS OF PROFITS, GOODWILL OR DATA. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR CERTAIN TYPES OF DAMAGES. THEREFORE, SOME OF THE ABOVE LIMITATIONS IN THIS SECTION MAY NOT APPLY TO A USER. IN PARTICULAR, NOTHING IN THESE TERMS SHALL AFFECT THE STATUTORY RIGHTS OF ANY USER OR EXCLUDE INJURY ARISING FROM ANY WILLFUL MISCONDUCT OR FRAUD OF STIFTUNG ETHEREUM**.
|
|
||||||
|
|
||||||
#### Dispute Resolution
|
|
||||||
|
|
||||||
All disputes or claims arising out of, relating to, or in connection with the Terms, the breach thereof, or use of the Ethereum Platform shall be finally settled under the Rules of Arbitration of the International Chamber of Commerce by one or more arbitrators appointed in accordance with said Rules. All claims between the parties relating to these Terms that are capable of being resolved by arbitration, whether sounding in contract, tort, or otherwise, shall be submitted to ICC arbitration. Prior to commencing arbitration, the parties have a duty to negotiate in good faith and attempt to resolve their dispute in a manner other than by submission to ICC arbitration. The arbitration panel shall consist of one arbitrator only, unless the ICC Court of Arbitration determines that the dispute is such as to warrant three arbitrators. If the Court determines that one arbitrator is sufficient, then such arbitrator shall be Swiss resident. If the Court determines that three arbitrators are necessary, then each party shall have 30 days to nominate an arbitrator of its choice -- in the case of the Claimant, measured from receipt of notification of the ICC Court’s decision to have three arbitrators; in the case of Respondent, measured from receipt of notification of Claimant’s nomination. All nominations must be Swiss resident. If a party fails to nominate an arbitrator, the Court will do so. The Court shall also appoint the chairman. All arbitrators shall be and remain “independent” of the parties involved in the arbitration. The place of arbitration shall be Zug, Switzerland. The language of the arbitration shall be English. In deciding the merits of the dispute, the tribunal shall apply the laws of Switzerland and any discovery shall be limited and shall not involve any depositions or any other examinations outside of a formal hearing. The tribunal shall not assume the powers of amiable compositeur or decide the case ex aequo et bono. In the final award, the tribunal shall fix the costs of the arbitration and decide which of the parties shall bear such costs in what proportion. Every award shall be binding on the parties. The parties undertake to carry out the award without delay and waive their right to any form of recourse against the award in so far as such waiver can validly be made.
|
|
||||||
|
|
||||||
#### Force Majeure
|
|
||||||
|
|
||||||
**STIFTUNG ETHEREUM** is finally not liable for:
|
|
||||||
|
|
||||||
* unavoidable casualty,
|
|
||||||
* delays in delivery of materials,
|
|
||||||
* embargoes,
|
|
||||||
* government orders,
|
|
||||||
* acts of civil or military authorities,
|
|
||||||
* lack of energy, or
|
|
||||||
* any similar unforeseen event that renders performance commercially implausible.
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
title: Ethereum specification
|
|
||||||
---
|
|
||||||
Specifications of all ethereum technologies, languages, protocols, etc.
|
|
||||||
|
|
||||||
### Whitepapers and design rationale
|
|
||||||
|
|
||||||
- [Ethereum Whitepaper](https://github.com/ethereum/wiki/wiki/White-Paper)
|
|
||||||
- [Design Rationale](https://github.com/ethereum/wiki/wiki/Design-Rationale)
|
|
||||||
- [Ethereum Yellow Paper](http://gavwood.com/Paper.pdf)
|
|
||||||
- [ÐΞVp2p Whitepaper](https://github.com/ethereum/wiki/wiki/libp2p-Whitepaper) (WiP)
|
|
||||||
- [Ethash](https://github.com/ethereum/wiki/wiki/Ethash)
|
|
||||||
|
|
||||||
### Specs
|
|
||||||
|
|
||||||
- [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API#a)
|
|
||||||
- [Generic JSON RPC](https://github.com/ethereum/wiki/JSON-RPC)
|
|
||||||
- [JSRE admin API](../interface/JavaScript-Console#console-api)
|
|
||||||
- [RLP](https://github.com/ethereum/wiki/wiki/RLP)
|
|
||||||
- [ÐΞVp2p Wire Protocol](https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol)
|
|
||||||
- [Web3 Secret Storage](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition)
|
|
||||||
- [Patricia Tree](https://github.com/ethereum/wiki/wiki/Patricia-Tree)
|
|
||||||
- [Wire protocol](https://github.com/ethereum/wiki/wiki/Ethereum-Wire-Protocol)
|
|
||||||
- [Light client protocol](https://github.com/ethereum/wiki/wiki/Light-client-protocol)
|
|
||||||
- [Solidity, Docs & ABI](https://github.com/ethereum/wiki/wiki/Solidity,-Docs-and-ABI)
|
|
||||||
- [NatSpec](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format)
|
|
||||||
- [Contract ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI)
|
|
||||||
- [Ethash](https://github.com/ethereum/wiki/wiki/Ethash)
|
|
||||||
- [Ethash C API](https://github.com/ethereum/wiki/wiki/Ethash-C-API)
|
|
||||||
- [Ethash DAG](https://github.com/ethereum/wiki/wiki/Ethash-DAG)
|
|
||||||
- [ICAP: Inter-exchange Client Address Protocol](https://github.com/ethereum/wiki/wiki/ICAP:-Inter-exchange-Client-Address-Protocol)
|
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
title: Ethereum on Android
|
|
||||||
---
|
|
||||||
Building Geth for Android is a non trivial task, as it requires cross compiling external C dependencies ([GNU Arithmetic Library](https://gmplib.org/)); internal C dependencies ([ethash](https://github.com/ethereum/ethash)); as well as the entire CGO enabled Go code-base to Android. This is further complicated by the Position Independent Executables (PIE) security feature introduced since Android 4.1 Jelly Bean, requiring different compiler and linker options based on the target Android platform version.
|
|
||||||
|
|
||||||
To cope with all the build issues, the [`xgo`](https://github.com/karalabe/xgo) CGO enabled Go cross compiler is used, which assembles an entire multi-platform cross compiler suite into a single mega docker container. Details about using `xgo` can be found in the project's [README](https://github.com/karalabe/xgo/blob/master/README.md), with Ethereum specifics on the go-ethereum cross compilation [wiki page](Cross-compiling-Ethereum).
|
|
||||||
|
|
||||||
TL;DR
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go get -u github.com/karalabe/xgo
|
|
||||||
$ xgo --deps=https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 \
|
|
||||||
--branch=develop \
|
|
||||||
--targets=android-16/arm \
|
|
||||||
github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
|
|
||||||
$ ls -al
|
|
||||||
-rwxr-xr-x 1 root root 23213348 Sep 14 19:35 geth-android-16-arm
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deploying a binary
|
|
||||||
|
|
||||||
Currently `xgo` will compile a native Android binary that can be copied onto a device and executed from a terminal emulator. As Ethereum Android support at the moment is mostly a developer feature, there have been no attempts at making it even remotely user friendly (installers, APKs, etc).
|
|
||||||
|
|
||||||
To push a native binary onto an Android device, you'll need an Android SDK installed. The most lightweight solution is the standalone [SDK Tools Only](https://developer.android.com/sdk/index.html#Other) package. Download and extract for your local machine's platform. Since building the binary is already done, we only need the [Android Debug Bridge](http://developer.android.com/tools/help/adb.html) to push it to our device, which can be installed using the SDK's `android` tool `$YOUR_SDK_PATH/tools/android` -> `Android SDK Platform Tools` (deselect everything else). We'll assume `$YOUR_SDK_PATH/platform-tools/adb` is in the PATH environmental variable from now on.
|
|
||||||
|
|
||||||
You can list the available devices via:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ adb devices
|
|
||||||
List of devices attached
|
|
||||||
0149CBF30201400E device
|
|
||||||
```
|
|
||||||
|
|
||||||
Deploying the binary to an Android device can be done in two steps. First copy the binary into the non-executable `sdcard` filesystem on the device. You may be asked the first time by the device to grant developer permission (also developer mode should be enabled on the devices prior).
|
|
||||||
|
|
||||||
```
|
|
||||||
$ adb push $PATH_TO_BINARY/geth-android-16-arm /sdcard/
|
|
||||||
1984 KB/s (23213348 bytes in 11.421s)
|
|
||||||
```
|
|
||||||
|
|
||||||
Then the binary needs to be moved to a file system with executable permissions, and said permissions need to be granted. On an unrooted phone the following path should be accessible with USB developer options.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ adb shell
|
|
||||||
$ cp /sdcard/geth-android-16-arm /data/local/tmp/geth
|
|
||||||
$ cd /data/local/tmp
|
|
||||||
$ chmod 751 geth
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running the deployed binary
|
|
||||||
|
|
||||||
After pushing the binary to the device and setting the appropriate permissions, you may execute Geth straight from the Android Debug Bridge shell:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./geth
|
|
||||||
I0911 11:09:05.329120 1427 cmd.go:125] Starting Geth/v1.1.0/android/go1.5.1
|
|
||||||
I0911 11:09:05.466782 1427 server.go:311] Starting Server
|
|
||||||
I0911 11:09:05.823965 1427 udp.go:207] Listening, enode://824e1a16bd6cb9931bec1ab6268cd76571936d5674505d53c7409b2b860cd9e396a66c7fe4c3ad4e60c43fe42408920e33aaf3e7bbdb6123f8094dbc423c2bb1@[::]:30303
|
|
||||||
I0911 11:09:05.832037 1427 backend.go:560] Server started
|
|
||||||
I0911 11:09:05.848936 1427 server.go:552] Listening on [::]:30303
|
|
||||||
```
|
|
||||||
|
|
||||||
A fancier way would be to start a terminal emulator on the Android device itself and run the binary expressly from it (remember, deployed at `/data/local/tmp/geth`):
|
|
||||||
|
|
||||||
![Geth on Android](http://i.imgur.com/wylOsBL.jpg)
|
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
title: Gas price oracle
|
|
||||||
---
|
|
||||||
The gas price oracle is a helper function of the Geth client that tries to find an appropriate default gas price when sending transactions. It can be parametrized with the following command line options:
|
|
||||||
|
|
||||||
- gpomin: lower limit of suggested gas price. This should be set at least as high as the "gasprice" setting usually used by miners so that your transactions will not be rejected automatically because of a too low price.
|
|
||||||
|
|
||||||
- gpomax: higher limit of suggested gas price. During load peaks when there is a competition between transactions to get into the blocks, the price needs to be limited, otherwise the oracle would eventually try to overbid everyone else at any price.
|
|
||||||
|
|
||||||
- gpofull: a block is considered "full" when a certain percentage of the block gas limit (specified in percents) is used up by transactions. If a block is not "full", that means that a transaction could have been accepted even with a minimal price offered.
|
|
||||||
|
|
||||||
- gpobasedown: an exponential ratio (specified in 1/1000ths) by which the base price decreases when the lowest acceptable price of the last block is below the last base price.
|
|
||||||
|
|
||||||
- gpobaseup: an exponential ratio (specified in 1/1000ths) by which the base price increases when the lowest acceptable price of the last block is over the last base price.
|
|
||||||
|
|
||||||
- gpobasecf: a correction factor (specified in percents) of the base price. The suggested price is the corrected base price, limited by gpomin and gpomax.
|
|
||||||
|
|
||||||
The lowest acceptable price is defined as a price that could have been enough to insert a transaction into a certain block. Although this value varies slightly with the gas used by the particular transaction, it is aproximated as follows: if the block is full, it is the lowest transaction gas price found in that block. If the block is not full, it equals to gpomin.
|
|
||||||
|
|
||||||
The base price is a moving value that is adjusted from block to block, up if it was lower than the lowest acceptable price, down otherwise. Note that there is a slight amount of randomness added to the correction factors so that your client will not behave absolutely predictable on the market.
|
|
||||||
|
|
||||||
If you want to specify a constant for the default gas price and not use the oracle, set both gpomin and gpomax to the same value.
|
|
|
@ -1 +0,0 @@
|
||||||
Moved: [Management APIs](Management-APIs)
|
|
|
@ -1,100 +0,0 @@
|
||||||
---
|
|
||||||
title: How to Whisper
|
|
||||||
---
|
|
||||||
Whisper is a pure identity-based messaging system. Whisper provides a low-level (non-application-specific) but easily-accessible API without being based upon or prejudiced by the low-level hardware attributes and characteristics, particularly the notion of singular endpoints.
|
|
||||||
|
|
||||||
This tutorial assumes you've read [p2p 101](Peer-to-Peer). If you haven't read it I suggest you read it. This tutorial will guide you to setting up a full p2p server with whisper capabilities.
|
|
||||||
|
|
||||||
Let's quickly cover some of whisper's basic functionality and discuss it in greater detail later.
|
|
||||||
|
|
||||||
```go
|
|
||||||
whisper.Send(myEnvelope)
|
|
||||||
```
|
|
||||||
|
|
||||||
The notion of envelopes and messages in whisper is somewhat blurred. An application shouldn't ever need to know the difference between the two and should only care about the information it's interested in. Therefor whisper comes with a subscribing mechanism which allows you watch/listen for specific whisper messages (e.g., to you, with a specific topic, etc).
|
|
||||||
|
|
||||||
```go
|
|
||||||
whisper.Watch(Filter{
|
|
||||||
From: myFriendsPubKey,
|
|
||||||
Fn: func(msg *whisper.Message) { /* ... */ },
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Envelopes & Messages
|
|
||||||
|
|
||||||
Whenever you want to send message over the whisper network you need to prove to network you've done some significant work for sealing the message (such is the cost for sending messages) and thus the more work you put in to sealing the message the higher the priority the message will have when propagating it over the network.
|
|
||||||
|
|
||||||
Whisper's *P*roof *o*f *W*ork consists of a simple SHA3 algorithm in which we try to find the smallest number within a given time frame. Giving the algorithm more time will result in a smaller number which means the message has a higher priority in the network.
|
|
||||||
|
|
||||||
Messages are also sealed with a *T*ime *T*o *L*ive. Whisper peers will automatically flush out messages which have exceeded their time to live (with a maximum up to 2 days).
|
|
||||||
|
|
||||||
Additionally messages may also contain a recipient (public key) and a set of topics. Topics will allow us to specify messages their subject (e.g., "shoes", "laptop", "marketplace", "chat"). Topics are automatically hashed and only the first 4 bytes are used during transmission and as such, topics are not 100% reliable, they should be treated as a probabilistic message filter.
|
|
||||||
|
|
||||||
Sending a whisper message requires you to:
|
|
||||||
|
|
||||||
1. create a new `whisper.Message`
|
|
||||||
2. `Seal` it (optionally encrypt, sign and supply with topics)
|
|
||||||
3. `Send` it to your peers
|
|
||||||
|
|
||||||
```go
|
|
||||||
topics := TopicsFromString("my", "message")
|
|
||||||
msg := whisper.NewMessage([]byte("hello world")) // 1
|
|
||||||
envelope := msg.Seal(whisper.Opts{ // 2
|
|
||||||
From: myPrivateKey, // Sign it
|
|
||||||
Topics: topics,
|
|
||||||
})
|
|
||||||
whisper.Send(envelope) // 3
|
|
||||||
```
|
|
||||||
|
|
||||||
Whenever a message needs to be encrypted for a specific recipient supply the `Opts` struct with an additional `To` parameter which accepts the recipients public key (`ecdsa.PublicKey`).
|
|
||||||
|
|
||||||
## Watching & Listening
|
|
||||||
|
|
||||||
Watching for specific messages on the whisper network can be done using the `Watch` method. You have the option to watch for messages from a specific recipient, with specific topics or messages directly directed to you.
|
|
||||||
|
|
||||||
```go
|
|
||||||
topics := TopicsFromString("my", "message")
|
|
||||||
whisper.Watch(Filter{
|
|
||||||
Topics: topics
|
|
||||||
Fn: func(msg *Message) {
|
|
||||||
fmt.Println(msg)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Connecting it all together
|
|
||||||
|
|
||||||
Now if we tie it all together and supply whisper as a sub-protocol to the DEV's P2P service we have whisper including peer handling and message propagation.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/whisper"
|
|
||||||
"github.com/obscuren/secp256k1-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pub, _ := secp256k1.GenerateKeyPair()
|
|
||||||
|
|
||||||
whisper := whisper.New()
|
|
||||||
|
|
||||||
srv := p2p.Server{
|
|
||||||
MaxPeers: 10,
|
|
||||||
Identity: p2p.NewSimpleClientIdentity("my-whisper-app", "1.0", "", string(pub)),
|
|
||||||
ListenAddr: ":8000",
|
|
||||||
Protocols: []p2p.Protocol{whisper.Protocol()},
|
|
||||||
}
|
|
||||||
if err := srv.Start(); err != nil {
|
|
||||||
fmt.Println("could not start server:", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {}
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1 +0,0 @@
|
||||||
see here https://github.com/ethersphere/go-ethereum/wiki/IPFS--SWARM
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for ARM
|
|
||||||
---
|
|
||||||
|
|
||||||
Geth is built for ARM using cross-compilation. See [Cross compiling Ethereum](Cross-compiling-Ethereum) for more details.
|
|
||||||
|
|
||||||
## RasPi 2
|
|
||||||
|
|
||||||
1. Download the precompiled binary from https://geth.ethereum.org/downloads/
|
|
||||||
1. Copy it to a location in $PATH (i.e. /usr/local/bin)
|
|
||||||
1. Run `geth`
|
|
||||||
|
|
||||||
Further details: https://github.com/ethereum/wiki/wiki/Raspberry-Pi-instructions
|
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for Arch
|
|
||||||
---
|
|
||||||
## Installing using pacman
|
|
||||||
|
|
||||||
The `geth` package is available from the [community repo](https://www.archlinux.org/packages/community/x86_64/geth/).
|
|
||||||
|
|
||||||
You can install it using
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pacman -S geth
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installing from source
|
|
||||||
Install dependencies
|
|
||||||
```shell
|
|
||||||
pacman -S git go gcc
|
|
||||||
```
|
|
||||||
|
|
||||||
Download and build geth
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/ethereum/go-ethereum
|
|
||||||
cd go-ethereum
|
|
||||||
make geth
|
|
||||||
```
|
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for FreeBSD
|
|
||||||
---
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
### Installing binary package
|
|
||||||
|
|
||||||
Binary packages tend not to be up to date (1.8.9 at the time of writing) with the latest version (1.8.16 at the time of writing). It is recommended that you use ports or compile it yourself.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pkg install go-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
The `geth` command is then available on your system in `/usr/local/bin/geth`, you can start it e.g. on the testnet by typing:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
geth -rinkeby
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using ports
|
|
||||||
|
|
||||||
Go to the `net-p2p/go-ethereum` ports directory:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd /usr/ports/net-p2p/go-ethereum
|
|
||||||
```
|
|
||||||
Then build it the standard way (as root):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building Geth (command line client)
|
|
||||||
|
|
||||||
Ports are slightly more up to date (1.8.14 at the time of writing)
|
|
||||||
|
|
||||||
Clone the repository to a directory of your choosing:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/ethereum/go-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
Building `geth` requires the Go compiler:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pkg install go
|
|
||||||
```
|
|
||||||
|
|
||||||
If your golang version is >= 1.5, build the `geth` program using the following command.
|
|
||||||
```shell
|
|
||||||
cd go-ethereum
|
|
||||||
make geth
|
|
||||||
```
|
|
||||||
If your golang version is < 1.5 (quarterly packages, for example), use the following command instead.
|
|
||||||
```shell
|
|
||||||
cd go-ethereum
|
|
||||||
CC=clang make geth
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now run `build/bin/geth` to start your node.
|
|
|
@ -1,58 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for Mac
|
|
||||||
---
|
|
||||||
## Installing with Homebrew
|
|
||||||
|
|
||||||
By far the easiest way to install go-ethereum is to use our
|
|
||||||
Homebrew tap. If you don't have Homebrew, [install it first](http://brew.sh).
|
|
||||||
|
|
||||||
Then run the following commands to add the tap and install `geth`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew tap ethereum/ethereum
|
|
||||||
brew install ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
You can install the develop branch by running `--devel`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew install ethereum --devel
|
|
||||||
```
|
|
||||||
|
|
||||||
After installing, run `geth account new` to create an account on your node.
|
|
||||||
|
|
||||||
You should now be able to run `geth` and connect to the network.
|
|
||||||
|
|
||||||
Make sure to check the different options and commands with `geth --help`
|
|
||||||
|
|
||||||
For options and patches, see: https://github.com/ethereum/homebrew-ethereum
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
### Building Geth (command line client)
|
|
||||||
|
|
||||||
Clone the repository to a directory of your choosing:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/ethereum/go-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
Building `geth` requires the Go compiler:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew install go
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, build the `geth` program using the following command.
|
|
||||||
```shell
|
|
||||||
cd go-ethereum
|
|
||||||
make geth
|
|
||||||
```
|
|
||||||
|
|
||||||
If you see some errors related to header files of Mac OS system library, install XCode Command Line Tools, and try again.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
xcode-select --install
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now run `build/bin/geth` to start your node.
|
|
|
@ -1,48 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for Ubuntu
|
|
||||||
---
|
|
||||||
## Installing from PPA
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt-get install software-properties-common
|
|
||||||
sudo add-apt-repository -y ppa:ethereum/ethereum
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to stay on the bleeding edge, install the `ethereum-unstable` package instead.
|
|
||||||
|
|
||||||
After installing, run `geth account new` to create an account on your node.
|
|
||||||
|
|
||||||
You should now be able to run `geth` and connect to the network.
|
|
||||||
|
|
||||||
Make sure to check the different options and commands with `geth --help`
|
|
||||||
|
|
||||||
You can alternatively install only the `geth` CLI with `apt-get install geth` if you don't want to install the other utilities (`bootnode`, `evm`, `disasm`, `rlpdump`, `ethtest`).
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
### Building Geth (command line client)
|
|
||||||
|
|
||||||
Clone the repository to a directory of your choosing:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
git clone https://github.com/ethereum/go-ethereum
|
|
||||||
```
|
|
||||||
Install latest distribution of Go (v1.7) if you don't have it already:
|
|
||||||
|
|
||||||
[See instructions](Installing-Go#ubuntu-1404)
|
|
||||||
|
|
||||||
Building `geth` requires Go and C compilers to be installed:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt-get install -y build-essential golang
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, build the `geth` program using the following command.
|
|
||||||
```shell
|
|
||||||
cd go-ethereum
|
|
||||||
make geth
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now run `build/bin/geth` to start your node.
|
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
title: Installation instructions for Windows
|
|
||||||
---
|
|
||||||
# Binaries
|
|
||||||
|
|
||||||
## Download stable binaries
|
|
||||||
|
|
||||||
All versions of Geth are built and available for download at https://geth.ethereum.org/downloads/.
|
|
||||||
|
|
||||||
The download page provides an installer as well as a zip file. The installer puts geth into your
|
|
||||||
PATH automatically. The zip file contains the command .exe files and can be used without installing.
|
|
||||||
|
|
||||||
1. Download zip file
|
|
||||||
1. Extract geth.exe from zip
|
|
||||||
1. Open a command prompt
|
|
||||||
1. chdir <path to geth.exe>
|
|
||||||
1. open geth.exe
|
|
||||||
|
|
||||||
# Source
|
|
||||||
|
|
||||||
## Compiling geth with tools from chocolatey
|
|
||||||
|
|
||||||
The Chocolatey package manager provides an easy way to get
|
|
||||||
the required build tools installed. If you don't have chocolatey yet,
|
|
||||||
follow the instructions on https://chocolatey.org to install it first.
|
|
||||||
|
|
||||||
Then open an Administrator command prompt and install the build tools
|
|
||||||
we need:
|
|
||||||
|
|
||||||
```text
|
|
||||||
C:\Windows\system32> choco install git
|
|
||||||
C:\Windows\system32> choco install golang
|
|
||||||
C:\Windows\system32> choco install mingw
|
|
||||||
```
|
|
||||||
|
|
||||||
Installing these packages will set up the `Path` environment variable.
|
|
||||||
Open a new command prompt to get the new `Path`. The following steps don't
|
|
||||||
need Administrator privileges.
|
|
||||||
|
|
||||||
Please ensure that the installed Go version is 1.7 (or any later version).
|
|
||||||
|
|
||||||
First we'll create and set up a Go workspace directory layout,
|
|
||||||
then clone the source.
|
|
||||||
|
|
||||||
***OBS*** If, during the commands below, you get the following message:
|
|
||||||
```
|
|
||||||
WARNING: The data being saved is truncated to 1024 characters.
|
|
||||||
```
|
|
||||||
Then that means that the `setx` command will fail, and proceeding will truncate the `Path`/`GOPATH`. If this happens, it's better to abort, and try to make some more room in `Path` before trying again.
|
|
||||||
|
|
||||||
```text
|
|
||||||
C:\Users\xxx> set "GOPATH=%USERPROFILE%"
|
|
||||||
C:\Users\xxx> set "Path=%USERPROFILE%\bin;%Path%"
|
|
||||||
C:\Users\xxx> setx GOPATH "%GOPATH%"
|
|
||||||
C:\Users\xxx> setx Path "%Path%"
|
|
||||||
C:\Users\xxx> mkdir src\github.com\ethereum
|
|
||||||
C:\Users\xxx> git clone https://github.com/ethereum/go-ethereum src\github.com\ethereum\go-ethereum
|
|
||||||
C:\Users\xxx> cd src\github.com\ethereum\go-ethereum
|
|
||||||
C:\Users\xxx> go get -u -v golang.org/x/net/context
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, the command to compile geth is:
|
|
||||||
|
|
||||||
```text
|
|
||||||
C:\Users\xxx\src\github.com\ethereum\go-ethereum> go install -v ./cmd/...
|
|
||||||
```
|
|
|
@ -1,114 +0,0 @@
|
||||||
---
|
|
||||||
title: Installing Geth
|
|
||||||
---
|
|
||||||
The Go implementation of Ethereum can be installed using a variety of ways. These include obtaining it as part of Mist; installing it via your favorite package manager; downloading a standalone pre-built bundle; running as a docker container; or building it yourself. This document will detail all of these possibilities to get you quickly joining the Ethereum network using whatever means you prefer.
|
|
||||||
|
|
||||||
* [Install from a package manager](#install-from-a-package-manager)
|
|
||||||
* [Install on macOS via Homebrew](#install-on-macos-via-homebrew)
|
|
||||||
* [Install on Ubuntu via PPAs](#install-on-ubuntu-via-ppas)
|
|
||||||
* [Install on Windows via Chocolatey](#install-on-windows-via-chocolatey)
|
|
||||||
* [Download standalone bundle](#download-standalone-bundle)
|
|
||||||
* [Run inside docker container](#run-inside-docker-container)
|
|
||||||
* [Build it from source code](#build-it-from-source-code)
|
|
||||||
* [Building without a Go workflow](#building-without-a-go-workflow)
|
|
||||||
|
|
||||||
## Install from a package manager
|
|
||||||
|
|
||||||
### Install on macOS via Homebrew
|
|
||||||
|
|
||||||
### Install on Ubuntu via PPAs
|
|
||||||
|
|
||||||
The simplest way to install go-ethereum on Ubuntu distributions is via the built in launchpad PPAs (Personal Package Archives). We provide a single PPA repository that contains both our stable as well as our develop releases for Ubuntu versions `trusty`, `xenial`, `zesty` and `artful`.
|
|
||||||
|
|
||||||
To enable our launchpad repository please run:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo add-apt-repository -y ppa:ethereum/ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
After that you can install the stable version of Go Ethereum:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
Or the develop version via:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install ethereum-unstable
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install on Windows via Chocolatey
|
|
||||||
|
|
||||||
Although we were shipping Chocolatey packages for a time after Frontier, it has fallen out of date due to the constant manual approval process. With our new build infrastructure in place we will attempt to negotiate trusted package status for go-ethereum to be able to reinstate the Chocolatey workflow. Until then please grab a Windows installer from our [downloads](https://geth.ethereum.org/downloads) page.
|
|
||||||
|
|
||||||
## Download standalone bundle
|
|
||||||
|
|
||||||
All our stable releases and develop builds are distributed as standalone bundles too. These can be useful for scenarios where you'd like to: a) install a specific version of our code (e.g. for reproducible environments); b) install on machines without internet access (e.g. air gapped computers); or c) simply do not like automatic updates and would rather manually install software.
|
|
||||||
|
|
||||||
We create the following standalone bundles:
|
|
||||||
|
|
||||||
* 32bit, 64bit, ARMv5, ARMv6, ARMv7 and ARM64 archives (`.tar.gz`) on Linux
|
|
||||||
* 64bit archives (`.tar.gz`) on macOS
|
|
||||||
* 32bit and 64bit archives (`.zip`) and installers (`.exe`) on Windows
|
|
||||||
|
|
||||||
For all archives we provide separate ones containing only Geth, and separate ones containing Geth along with all the developer tools from our repository (`abigen`, `bootnode`, `disasm`, `evm`, `rlpdump`). Please see our [`README`](https://github.com/ethereum/go-ethereum#executables) for more information about these executables.
|
|
||||||
|
|
||||||
To download these bundles, please head the [Go Ethereum Downloads](https://geth.ethereum.org/downloads) page.
|
|
||||||
|
|
||||||
## Run inside docker container
|
|
||||||
|
|
||||||
If you prefer containerized processes, you can run go-ethereum as a docker container too. We currently maintain four different docker images for running the latest stable or develop versions of Geth.
|
|
||||||
|
|
||||||
* `ethereum/client-go:latest` is the latest develop version of Geth
|
|
||||||
* `ethereum/client-go:stable` is the latest stable version of Geth
|
|
||||||
* `ethereum/client-go:{version}` is the stable version of Geth at a specific version number
|
|
||||||
* `ethereum/client-go:release-{version}` is the latest stable version of Geth at a specific version family
|
|
||||||
|
|
||||||
We also maintain four different docker images for running the latest stable or develop versions of miscellaneous Ethereum tools.
|
|
||||||
|
|
||||||
* `ethereum/client-go:alltools-latest` is the latest develop version of the Ethereum tools
|
|
||||||
* `ethereum/client-go:alltools-stable` is the latest stable version of the Ethereum tools
|
|
||||||
* `ethereum/client-go:alltools-{version}` is the stable version of the Ethereum tools at a specific version number
|
|
||||||
* `ethereum/client-go:alltools-release-{version}` is the latest stable version of the Ethereum tools at a specific version family
|
|
||||||
|
|
||||||
The image has the following ports automatically exposed:
|
|
||||||
|
|
||||||
* `8545` TCP, used by the HTTP based JSON RPC API
|
|
||||||
* `8546` TCP, used by the WebSocket based JSON RPC API
|
|
||||||
* `30303` TCP and UDP, used by the P2P protocol running the network
|
|
||||||
* `30304` UDP, used by the P2P protocol's new peer discovery overlay
|
|
||||||
|
|
||||||
*Note, if you are running an Ethereum client inside a docker container, you might want to mount in a data volume as the client's data directory (located at `/root/.ethereum` inside the container) to ensure that downloaded data is preserved between restarts and/or container life-cycles.*
|
|
||||||
|
|
||||||
## Build it from source code
|
|
||||||
|
|
||||||
Go Ethereum (as its name implies) is written in [Go](https://golang.org), and as such to build from source code you'll need to ensure that you have at least Go 1.7 installed (preferably the latest version, currently at 1.9.2). This guide will not go into details on how to install Go itself, for that please consult the [Go installation instructions](https://golang.org/doc/install) and grab any needed bundles from the [Go download page](https://golang.org/dl/).
|
|
||||||
|
|
||||||
Assuming you have Go installed, you can download our project via:
|
|
||||||
|
|
||||||
```
|
|
||||||
go get -d github.com/ethereum/go-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
The above command will checkout the default version of Go Ethereum into your local `GOPATH` work space, but it will not build any executables for you. To do that you can either build one specifically:
|
|
||||||
|
|
||||||
```
|
|
||||||
go install github.com/ethereum/go-ethereum/cmd/geth
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you can also build the entire project and install `geth` along with all developer tools by running `go install ./...` in the repository root inside your `GOPATH` work space.
|
|
||||||
|
|
||||||
### Building without a Go workflow
|
|
||||||
|
|
||||||
If you do not want to set up Go work spaces on your machine, only build `geth` and forget about the build process, you can clone our repository directly into a folder of your choosing and invoke `make`, which will configure everything for a temporary build and clean up after itself:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/ethereum/go-ethereum.git
|
|
||||||
cd go-ethereum
|
|
||||||
make geth
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create a `geth` (or `geth.exe` on Windows) executable file in the `go-ethereum/build/bin` folder that you can move wherever you want to run from. The binary is standalone and doesn't require any additional files.
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
title: Installing Go
|
|
||||||
---
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
Download and run the installer found at http://golang.org/doc/install
|
|
||||||
|
|
||||||
### OS X
|
|
||||||
|
|
||||||
Download an install the darwin binary from https://golang.org/dl/
|
|
||||||
|
|
||||||
You can also install go using the Homebrew package manager.
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||
#### Ubuntu
|
|
||||||
|
|
||||||
The Ubuntu repositories carry an old version of Go.
|
|
||||||
|
|
||||||
Ubuntu users can use the 'gophers' PPA to install an up to date version of Go (version 1.7 or later is preferred).
|
|
||||||
See https://launchpad.net/~gophers/+archive/ubuntu/archive for more information.
|
|
||||||
Note that this PPA requires adding `/usr/lib/go-1.X/bin` to the executable PATH.
|
|
||||||
|
|
||||||
#### Other distros
|
|
||||||
|
|
||||||
Download the latest distribution
|
|
||||||
|
|
||||||
`curl -O https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz`
|
|
||||||
|
|
||||||
Unpack it to the `/usr/local` (might require sudo)
|
|
||||||
|
|
||||||
`tar -C /usr/local -xzf go1.7.3.linux-amd64.tar.gz`
|
|
||||||
|
|
||||||
#### Set GOPATH and PATH
|
|
||||||
|
|
||||||
For Go to work properly, you need to set the following two environment variables:
|
|
||||||
|
|
||||||
- Setup a go folder `mkdir -p ~/go; echo "export GOPATH=$HOME/go" >> ~/.bashrc`
|
|
||||||
- Update your path `echo "export PATH=$PATH:$HOME/go/bin:/usr/local/go/bin" >> ~/.bashrc`
|
|
||||||
- Read the environment variables into current session: `source ~/.bashrc`
|
|
|
@ -1,397 +0,0 @@
|
||||||
---
|
|
||||||
title: Contracts and transactions (Japanese)
|
|
||||||
---
|
|
||||||
THIS WIKI IS BEING EDITED AND REVIEWED NOW. PLEASE DO NOT RELY ON IT.
|
|
||||||
|
|
||||||
# Account types and transactions
|
|
||||||
|
|
||||||
There are two types of accounts in Ethereum state:
|
|
||||||
* Normal or externally controlled accounts and
|
|
||||||
* contracts, i.e., sinppets of code, think a class.
|
|
||||||
|
|
||||||
Both types of accounts have an ether balance.
|
|
||||||
|
|
||||||
Transactions can be fired from from both types of accounts, though contracts only fire transactions in response to other transactions that they have received. Therefore, all action on ethereum block chain is set in motion by transactions fired from externally controlled accounts.
|
|
||||||
|
|
||||||
The simplest transactions are ether transfer transactions. But before we go into that you should read up on [accounts](../how-to/Managing-your-accounts) and perhaps on [mining](../how-to/Mining).
|
|
||||||
|
|
||||||
## Ether transfer
|
|
||||||
|
|
||||||
Assuming the account you are using as sender has sufficient funds, sending ether couldn't be easier. Which is also why you should probably be careful with this! You have been warned.
|
|
||||||
|
|
||||||
```js
|
|
||||||
eth.sendTransaction({from: '0x036a03fc47084741f83938296a1c8ef67f6e34fa', to: '0xa8ade7feab1ece71446bed25fa0cf6745c19c3d5', value: web3.toWei(1, "ether")})
|
|
||||||
```
|
|
||||||
|
|
||||||
Note the unit conversion in the `value` field. Transaction values are expressed in weis, the most granular units of value. If you want to use some other unit (like `ether` in the example above), use the function `web3.toWei` for conversion.
|
|
||||||
|
|
||||||
Also, be advised that the amount debited from the source account will be slightly larger than that credited to the target account, which is what has been specified. The difference is a small transaction fee, discussed in more detail later.
|
|
||||||
|
|
||||||
Contracts can receive transfers just like externally controlled accounts, but they can also receive more complicated transactions that actually run (parts of) their code and update their state. In order to understand those transactions, a rudimentary understanding of contracts is required.
|
|
||||||
|
|
||||||
# contract のコンパイル
|
|
||||||
|
|
||||||
blockchain 上で有効となる contract は Ethereum 特別仕様の バイナリの形式で、EVM byte コード と呼ばれます。
|
|
||||||
しかしながら、典型的には、contract は [solidity](https://github.com/ethereum/wiki/wiki/Solidity-Tutorial) のような高級言語で記述され、blockchain 上に upload するために、この byte コードへコンパイルされます。
|
|
||||||
|
|
||||||
flontier リリースでは、geth は Christian R. と Lefteris K が手がけた、コマンドライン [solidity コンパイラ](https://github.com/ethereum/cpp-ethereum/tree/develop/solc) である `solc` をシステムコールで呼び出すことを通して、solidity コンパイルをサポートしています。
|
|
||||||
以下もお試しください。
|
|
||||||
* [Solidity realtime compiler](https://chriseth.github.io/cpp-ethereum/) (by Christian R)
|
|
||||||
* [Cosmo](http://meteor-dapp-cosmo.meteor.com)
|
|
||||||
* [Mix]()
|
|
||||||
* [AlethZero]()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Note that other languages also exist, notably [serpent]() and [lll]().
|
|
||||||
|
|
||||||
If you start up your `geth` node, you can check if this option is immediately available. This is what happens, if it is not:
|
|
||||||
|
|
||||||
```js
|
|
||||||
eth.getCompilers()
|
|
||||||
['' ]
|
|
||||||
> eth.compile.solidity("")
|
|
||||||
error: eth_compileSolidity method not implemented
|
|
||||||
Invalid JSON RPC response
|
|
||||||
```
|
|
||||||
|
|
||||||
After you found a way to install `solc`, you make sure it's in the path, if [`eth.getCompilers()`](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgetcompilers) still does not find it (returns an empty array), you can set a custom path to the `sol` executable on the command line using th `solc` flag.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --datadir ~/frontier/00 --solc /usr/local/bin/solc --natspec
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also set this option at runtime via the console:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> admin.setSolc("/usr/local/bin/solc")
|
|
||||||
solc v0.9.13
|
|
||||||
Solidity Compiler: /usr/local/bin/solc
|
|
||||||
Christian <c@ethdev.com> and Lefteris <lefteris@ethdev.com> (c) 2014-2015
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
Let us take this simple contract source:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"
|
|
||||||
```
|
|
||||||
|
|
||||||
This contract offers a unary method: called with a positive integer `a`, it returns `a * 7`.
|
|
||||||
Note that this document is not about writing interesting contracts or about the features of solidity.
|
|
||||||
|
|
||||||
For more information on contract language, go through [solidity tutorial](https://github.com/ethereum/wiki/wiki/Solidity-Tutorial), browse the contracts in our [dapp-bin](https://github.com/ethereum/dapp-bin/wiki), see other solidity and dapp resources.
|
|
||||||
|
|
||||||
You are ready to compile solidity code in the `geth` JS console using [`eth.compile.solidity`](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcompilesolidity):
|
|
||||||
|
|
||||||
```js
|
|
||||||
> contract = eth.compile.solidity(source)
|
|
||||||
{
|
|
||||||
code: '605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056',
|
|
||||||
info: {
|
|
||||||
language: 'Solidity',
|
|
||||||
languageVersion: '0',
|
|
||||||
compilerVersion: '0.9.13',
|
|
||||||
abiDefinition: [{
|
|
||||||
constant: false,
|
|
||||||
inputs: [{
|
|
||||||
name: 'a',
|
|
||||||
type: 'uint256'
|
|
||||||
} ],
|
|
||||||
name: 'multiply',
|
|
||||||
outputs: [{
|
|
||||||
name: 'd',
|
|
||||||
type: 'uint256'
|
|
||||||
} ],
|
|
||||||
type: 'function'
|
|
||||||
} ],
|
|
||||||
userDoc: {
|
|
||||||
methods: {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
developerDoc: {
|
|
||||||
methods: {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
source: 'contract test { function multiply(uint a) returns(uint d) { return a * 7; } }'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The compiler is also available via [RPC](https://github.com/ethereum/wiki/JSON-RPC) and therefore via [web3.js](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcompilesolidity) to any in-browser Ðapp connecting to `geth` via RPC.
|
|
||||||
|
|
||||||
The following example shows how you interface `geth` via JSON-RPC to use the compiler.
|
|
||||||
|
|
||||||
```
|
|
||||||
./geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain '*' --mine console 2>> ~/eth/eth.log
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"],"id":1}' http://127.0.0.1:8100
|
|
||||||
```
|
|
||||||
|
|
||||||
The compiler output is combined into an object representing a single contract and is serialised as json. It contains the following fields:
|
|
||||||
|
|
||||||
* `code`: the compiled EVM code
|
|
||||||
* `source`: the source code
|
|
||||||
* `language`: contract language (Solidity, Serpent, LLL)
|
|
||||||
* `languageVersion`: contract language version
|
|
||||||
* `compilerVersion`: compiler version
|
|
||||||
* `abiDefinition`: [Application Binary Interface Definition](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI)
|
|
||||||
* `userDoc`: [NatSpec user Doc](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format)
|
|
||||||
* `developerDoc`: [NatSpec developer Doc](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format)
|
|
||||||
|
|
||||||
The immediate structuring of the compiler output (into `code` and `info`) reflects the two very different **paths of deployment**.
|
|
||||||
The compiled EVM code is sent off to the blockchain with a contract creation transaction while the rest (info) will ideally live on the decentralised cloud as publicly verifiable metadata complementing the code on the blockchain.
|
|
||||||
|
|
||||||
# Creating and deploying a contract
|
|
||||||
|
|
||||||
Now that you got both an unlocked account as well as some funds, you can create a contract on the blockchain by [sending a transaction](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethsendtransaction) to the empty address with the evm code as data. Simple, eh?
|
|
||||||
|
|
||||||
```js
|
|
||||||
primaryAddress = eth.accounts[0]
|
|
||||||
contractAddress = eth.sendTransaction({from: primaryAddress, data: evmCode})
|
|
||||||
```
|
|
||||||
|
|
||||||
All binary data is serialised in hexadecimal form. Hex strings always have a hex prefix `0x`.
|
|
||||||
|
|
||||||
Note that this step requires you to pay for execution. Your balance on the account (that you put as sender in the `from` field) will be reduced according to the gas rules of the VM once your transaction makes it into a block. More on that later. After some time, your transaction should appear included in a block confirming that the state it brought about is a consensus. Your contract now lives on the blockchain.
|
|
||||||
|
|
||||||
The asynchronous way of doing the same looks like this:
|
|
||||||
|
|
||||||
```js
|
|
||||||
eth.sendTransaction({from: primaryAccount, data: evmCode}, function(err, address) {
|
|
||||||
if (!err)
|
|
||||||
console.log(address);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
# Gas and transaction costs
|
|
||||||
|
|
||||||
So how did you pay for all this? Under the hood, the transaction specified a gas limit and a gasprice, both of which could have been specified directly in the transaction object.
|
|
||||||
|
|
||||||
Gas limit is there to protect you from buggy code running until your funds are depleted. The product of `gasPrice` and `gas` represents the maximum amount of Wei that you are willing to pay for executing the transaction. What you specify as `gasPrice` is used by miners to rank transactions for inclusion in the blockchain. It is the price in Wei of one unit of gas, in which VM operations are priced.
|
|
||||||
|
|
||||||
The gas expenditure incurred by running your contract will be bought by the ether you have in your account at a price you specified in the transaction with `gasPrice`. If you do not have the ether to cover all the gas requirements to complete running your code, the processing aborts and all intermediate state changes roll back to the pre-transaction snapshot. The gas used up to the point where execution stopped were used after all, so the ether balance of your account will be reduced. These parameters can be adjusted on the transaction object fields `gas` and `gasPrice`. The `value` field is used the same as in ether transfer transactions between normal accounts. In other words transferring funds is available between any two accounts, either normal (i.e. externally controlled) or contract. If your contract runs out of funds, you should see an insufficient funds error. Note that all funds on contract accounts will be irrecoverably lost, once we release Homestead.
|
|
||||||
|
|
||||||
For testing and playing with contracts you can use the test network or set up a private node (or cluster) potentially isolated from all the other nodes. If you then mine, you can make sure that your transaction will be included in the next block. You can see the pending transactions with:
|
|
||||||
|
|
||||||
```js
|
|
||||||
eth.getBlock("pending", true).transactions
|
|
||||||
```
|
|
||||||
|
|
||||||
You can retrieve blocks by number (height) or by their hash:
|
|
||||||
|
|
||||||
```js
|
|
||||||
genesis = eth.getBlock(0)
|
|
||||||
eth.getBlock(genesis.hash).hash == genesis.hash
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `eth.blockNumber` to get the current blockchain height and the "latest" magic parameter to access the current head (newest block).
|
|
||||||
|
|
||||||
```js
|
|
||||||
currentHeight = eth.blockNumber()
|
|
||||||
eth.getBlock("latest").hash == eth.getBlock(eth.blockNumber).hash
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
# Contract info (metadata)
|
|
||||||
|
|
||||||
In the previous sections we explained how you create a contract on the blockchain. Now we deal with the rest of the compiler output, the **contract metadata** or contract info.
|
|
||||||
The idea is that
|
|
||||||
|
|
||||||
* contract info is uploaded somewhere identifiable by a `url` which is publicly accessible
|
|
||||||
* anyone can find out what the `url` is only knowing the contracts address
|
|
||||||
|
|
||||||
These requirements are achieved very simply by using a 2 step blockchain registry. The first step registers the contract code (hash) with a content hash in a contract called `HashReg`. The second step registers a url with the content hash in the `UrlHint` contract.
|
|
||||||
These [simple registry contracts]() will be part of the frontier proposition.
|
|
||||||
|
|
||||||
By using this scheme, it is sufficient to know a contract's address to look up the url and fetch the actual contract metadata info bundle. Read on to learn why this is good.
|
|
||||||
|
|
||||||
So if you are a conscientious contract creator, the steps are the following:
|
|
||||||
|
|
||||||
1. Get the contract info json file.
|
|
||||||
2. Deploy contract info json file to any url of your choice
|
|
||||||
3. Register codehash ->content hash -> url
|
|
||||||
4. Deploy the contract itself to the blockchain
|
|
||||||
|
|
||||||
The JS API makes this process very easy by providing helpers. Call [`admin.contractInfo.register`]() to extract info from the contract, write out its json serialisation in the given file, calculates the content hash of the file and finally registers this content hash to the contract's code hash.
|
|
||||||
Once you deployed that file to any url, you can use [`admin.contractInfo.registerUrl`]() to register the url with your content hash on the blockchain as well. (Note that in case a fixed content addressed model is used as document store, the url-hint is no longer necessary.)
|
|
||||||
|
|
||||||
```js
|
|
||||||
source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"
|
|
||||||
// compile with solc
|
|
||||||
contract = eth.compile.solidity(source)
|
|
||||||
// send off the contract to the blockchain
|
|
||||||
address = eth.sendTransaction({from: primaryAccount, data: contract.code})
|
|
||||||
// extracts info from contract, save the json serialisation in the given file,
|
|
||||||
// calculates the content hash and registers it with the code hash in `HashReg`
|
|
||||||
// it uses address to send the transaction.
|
|
||||||
// returns the content hash that we use to register a url
|
|
||||||
hash = admin.contractInfo.register(primaryAccount, address, contract, "~/dapps/shared/contracts/test/info.json")
|
|
||||||
// here you deploy ~/dapps/shared/contracts/test/info.json to a url
|
|
||||||
admin.contractInfo.registerUrl(primaryAccount, hash, url)
|
|
||||||
```
|
|
||||||
|
|
||||||
# Interacting with contracts
|
|
||||||
|
|
||||||
[`eth.contract`](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcontract) can be used to define a contract _class_ that will comply with the contract interface as described in its [ABI definition](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI).
|
|
||||||
|
|
||||||
```js
|
|
||||||
var Multiply7 = eth.contract(contract.info.abiDefinition);
|
|
||||||
var multiply7 = new Multiply7(address);
|
|
||||||
```
|
|
||||||
|
|
||||||
Now all the function calls specified in the abi are made available on the contract instance. You can just call those methods on the contract instance and chain `sendTransaction({from: address})` or `call()` to it. The difference between the two is that `call` performs a "dry run" locally, on your computer, while `sendTransaction` would actually submit your transaction for inclusion in the block chain and the results of its execution will eventually become part of the global consensus. In other words, use `call`, if you are interested only in the return value and use `sendTransaction` if you only care about "side effects" on the state of the contract.
|
|
||||||
|
|
||||||
In the example above, there are no side effects, therefore `sendTransaction` only burns gas and increases the entropy of the universe. All "useful" functionality is exposed by `call`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
multiply7.multiply.call(6)
|
|
||||||
42
|
|
||||||
```
|
|
||||||
|
|
||||||
Now suppose this contract is not yours, and you would like documentation or look at the source code.
|
|
||||||
This is made possible by making available the contract info bundle and register it in the blockchain.
|
|
||||||
The `admin.contractInfo` API provides convenience methods to fetch this bundle for any contract that chose to register.
|
|
||||||
To see how it works, read about [Contract Metadata](https://github.com/ethereum/wiki/wiki/Contract-metadata) or read the contract info deployment section of this document.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// get the contract info for contract address to do manual verification
|
|
||||||
var info = admin.contractInfo.get(address) // lookup, fetch, decode
|
|
||||||
var source = info.source;
|
|
||||||
var abiDef = info.abiDefinition
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
// verify an existing contract in blockchain (NOT IMPLEMENTED)
|
|
||||||
admin.contractInfo.verify(address)
|
|
||||||
```
|
|
||||||
|
|
||||||
# NatSpec
|
|
||||||
|
|
||||||
This section will further elaborate what you can do with contracts and transactions building on a protocol NatSpec. Solidity implements smart comments doxigen style which then can be used to generate various facades meta documents of the code. One such use case is to generate custom messages for transaction confirmation that clients can prompt users with.
|
|
||||||
|
|
||||||
So we now extend the `multiply7` contract with a smart comment specifying a custom confirmation message (notice).
|
|
||||||
|
|
||||||
```js
|
|
||||||
contract test {
|
|
||||||
/// @notice Will multiply `a` by 7.
|
|
||||||
function multiply(uint a) returns(uint d) {
|
|
||||||
return a * 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The comment has expressions in between backticks which are to be evaluated at the time the transaction confirmation message is presented to the user. The variables that refer to parameters of method calls then are instantiated in accordance with the actual transaction data sent by the user (or the user's dapp). NatSpec support for confirmation notices is fully implemented in `geth`. NatSpec relies on both the abi definition as well as the userDoc component to generate the proper confirmations. Therefore in order to access that, the contract needs to have registered its contract info as described above.
|
|
||||||
|
|
||||||
Let us see a full example. As a very conscientious smart contract dev, you first create your contract and deploy according to the recommended steps above:
|
|
||||||
|
|
||||||
```js
|
|
||||||
source = "contract test {
|
|
||||||
/// @notice Will multiply `a` by 7.
|
|
||||||
function multiply(uint a) returns(uint d) {
|
|
||||||
return a * 7;
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
contract = eth.compile.solidity(source)
|
|
||||||
contentHash = admin.contractInfo.register(contract, "~/dapps/shared/contracts/test/info.json")
|
|
||||||
// put it up on your favourite site:
|
|
||||||
admin.contractInfo.registerUrl(contentHash, "http://dapphub.com/test/info.json")
|
|
||||||
```
|
|
||||||
|
|
||||||
For the purposes of a painless example just simply use the file url scheme (not exactly the cloud, but will show you how it works) without needing to deploy. `admin.contractInfo.registerUrl(contentHash, "file:///home/nirname/dapps/shared/contracts/test/info.json")`.
|
|
||||||
|
|
||||||
Now you are done as a dev, so swap seats as it were and pretend that you are a user who is sending a transaction to the infamous multiply7 contract.
|
|
||||||
|
|
||||||
You need to start the client with the `--natspec` flag to enable smart confirmations and contractInfo fetching. You can also set it on the console with `admin.contractInfo.start()` and `admin.contractInfo.stop()`.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --natspec --unlock primary console 2>> /tmp/eth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
Now at the console type:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// obtain the abi definition for your contract
|
|
||||||
var info = admin.contractInfo.get(address)
|
|
||||||
var abiDef = info.abiDefinition
|
|
||||||
// instantiate a contract for transactions
|
|
||||||
var Multiply7 = eth.contract(abiDef);
|
|
||||||
var multiply7 = new Multiply7();
|
|
||||||
```
|
|
||||||
|
|
||||||
And now try to send an actual transaction:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> multiply7.multiply.sendTransaction(6)
|
|
||||||
NatSpec: Will multiply 6 by 7.
|
|
||||||
Confirm? [Y/N] y
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
When this transaction gets included in a block, somewhere on a lucky miner's computer, 6 will get multiplied by 7, with the result ignored.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// assume an existing unlocked primary account
|
|
||||||
primary = eth.accounts[0];
|
|
||||||
|
|
||||||
// mine 10 blocks to generate ether
|
|
||||||
admin.miner.start();
|
|
||||||
admin.debug.waitForBlocks(eth.blockNumber+10);
|
|
||||||
admin.miner.stop() ;
|
|
||||||
|
|
||||||
balance = web3.fromWei(eth.getBalance(primary), "ether");
|
|
||||||
|
|
||||||
admin.contractInfo.newRegistry(primary);
|
|
||||||
|
|
||||||
source = "contract test {\n" +
|
|
||||||
" /// @notice will multiply `a` by 7.\n" +
|
|
||||||
" function multiply(uint a) returns(uint d) {\n" +
|
|
||||||
" return a * 7;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"} ";
|
|
||||||
|
|
||||||
contract = eth.compile.solidity(source);
|
|
||||||
|
|
||||||
contractaddress = eth.sendTransaction({from: primary, data: contract.code});
|
|
||||||
|
|
||||||
eth.getBlock("pending", true).transactions;
|
|
||||||
|
|
||||||
admin.miner.start()
|
|
||||||
// waits until block height is minimum the number given.
|
|
||||||
// basically a sleep function on variable block units of time.
|
|
||||||
|
|
||||||
admin.debug.waitForBlocks(eth.blockNumber+1);
|
|
||||||
admin.miner.stop()
|
|
||||||
|
|
||||||
code = eth.getCode(contractaddress);
|
|
||||||
|
|
||||||
abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
|
|
||||||
Multiply7 = eth.contract(abiDef);
|
|
||||||
multiply7 = new Multiply7(contractaddress);
|
|
||||||
|
|
||||||
fortytwo = multiply7.multiply.call(6);
|
|
||||||
console.log("multiply7.multiply.call(6) => "+fortytwo);
|
|
||||||
multiply7.multiply.sendTransaction(6, {from: primary})
|
|
||||||
|
|
||||||
admin.miner.start();
|
|
||||||
admin.debug.waitForBlocks(eth.blockNumber+1);
|
|
||||||
admin.miner.stop();
|
|
||||||
|
|
||||||
filename = "/tmp/info.json";
|
|
||||||
contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename);
|
|
||||||
|
|
||||||
admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename);
|
|
||||||
|
|
||||||
admin.miner.start();
|
|
||||||
admin.debug.waitForBlocks(eth.blockNumber+1);
|
|
||||||
admin.miner.stop();
|
|
||||||
|
|
||||||
info = admin.contractInfo.get(contractaddress);
|
|
||||||
|
|
||||||
admin.contractInfo.start();
|
|
||||||
abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
|
|
||||||
Multiply7 = eth.contract(abiDef);
|
|
||||||
multiply7 = new Multiply7(contractaddress);
|
|
||||||
fortytwo = multiply7.multiply.sendTransaction(6, { from: primary });
|
|
||||||
|
|
||||||
```
|
|
|
@ -1,116 +0,0 @@
|
||||||
---
|
|
||||||
title: Metrics and monitoring
|
|
||||||
---
|
|
||||||
Geth has quite a nice logging system, capable of creating leveled log entries tagged with various parts of the system. This helps enormously during debugging to see exactly what the system is doing, what branches it's taking, etc. However, logs are not particularly useful when the system does work correctly, just not very optimally: one - or even a handful - of logged events is not really statistically relevant, and tracing more in log files can quickly become unwieldy.
|
|
||||||
|
|
||||||
The goal of the Geth metrics system is that - similar to logs - we should be able to add arbitrary metric collection to any part of the code without requiring fancy constructs to analyze them (counter variables, public interfaces, crossing over the APIs, console hooks, etc). Instead, we should just "update" metrics whenever and wherever needed, and have them automatically collected, surfaced through the APIs, queryable and visualizable for analysis.
|
|
||||||
|
|
||||||
To that extent, Geth currently implement two types of metrics:
|
|
||||||
* **Meters**: Analogous to physical meters (electricity, water, etc), they are capable of measuring the *amount* of "things" that pass through and at the *rate* at which they do that. A meter doesn't have a specific unit of measure (byte, block, malloc, etc), it just counts arbitrary *events*. At any point in time it can report:
|
|
||||||
* *Total number of events* that passed through the meter
|
|
||||||
* *Mean throughput rate* of the meter since startup (events / second)
|
|
||||||
* *Weighted throughput rate* in the last *1*, *5* and *15* minutes (events / second)
|
|
||||||
* (*"weighted" means that recent seconds count more that in older ones*)
|
|
||||||
* **Timers**: Extension of *meters*, where not only the occurrence of some event is measured, its *duration* is also collected. Similarly to meters, a timer can also measure arbitrary events, but each requires a duration to be assigned individually. Beside **all** the reports a meter can generate, a timer has additionally:
|
|
||||||
* *Percentiles (5, 20, 50, 80, 95)*, reporting that some percentage of the events took less than the reported time to execute (*e.g. Percentile 20 = 1.5s would mean that 20% of the measured events took less time than 1.5 seconds to execute; inherently 80%(=100%-20%) took more that 1.5s*)
|
|
||||||
* Percentile 5: minimum durations (this is as fast as it gets)
|
|
||||||
* Percentile 50: well behaved samples (boring, just to give an idea)
|
|
||||||
* Percentile 80: general performance (these should be optimised)
|
|
||||||
* Percentile 95: worst case outliers (rare, just handle gracefully)
|
|
||||||
|
|
||||||
## Creating and updating metrics
|
|
||||||
|
|
||||||
Although the Geth metrics system is based on the [`go-metrics`](https://github.com/rcrowley/go-metrics) library, custom metric constructors are used that take into consideration the CLI flags to enable or disable metrics collection and reporting:
|
|
||||||
|
|
||||||
```go
|
|
||||||
meter := metrics.NewMeter("system/memory/allocs")
|
|
||||||
timer := metrics.NewTimer("chain/inserts")
|
|
||||||
```
|
|
||||||
|
|
||||||
The name can be any arbitrary string, however since Geth assumes it to be some meaningful sub-system hierarchy, please name accordingly. Metrics can then be updated equally simply:
|
|
||||||
|
|
||||||
```go
|
|
||||||
meter.Mark(n) // Record the occurrence of `n` events
|
|
||||||
|
|
||||||
timer.Update(duration) // Record an event that took `duration`
|
|
||||||
timer.UpdateSince(time) // Record an event that started at `time`
|
|
||||||
timer.Time(function) // Measure and record the execution of `function`
|
|
||||||
```
|
|
||||||
|
|
||||||
Note, metrics collection is disabled by default in order not to incur reporting overhead for the average user. To enable it please specify the `--metrics` flag to geth.
|
|
||||||
|
|
||||||
## Querying metrics
|
|
||||||
|
|
||||||
Geth automatically exposes all collected metrics in the `debug` RPC API, through the `metrics` method, hence these can be queried simply from the console in:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
> debug.metrics().p2p.InboundTraffic
|
|
||||||
{
|
|
||||||
Avg01Min: '169.12K (2.82K/s)',
|
|
||||||
Avg05Min: '1.92M (6.42K/s)',
|
|
||||||
Avg15Min: '3.57M (3.96K/s)',
|
|
||||||
Total: '5.83M (2.97K/s)'
|
|
||||||
}
|
|
||||||
> debug.metrics().chain.inserts
|
|
||||||
{
|
|
||||||
Avg01Min: '10 (0.17/s)',
|
|
||||||
Avg05Min: '61 (0.20/s)',
|
|
||||||
Avg15Min: '168 (0.19/s)',
|
|
||||||
Maximum: '2.157261657s',
|
|
||||||
Minimum: '2.271716ms',
|
|
||||||
Percentiles: {
|
|
||||||
20: '6.993756ms',
|
|
||||||
50: '12.342836ms',
|
|
||||||
80: '21.765944ms',
|
|
||||||
95: '218.500479ms',
|
|
||||||
99: '376.015984ms'
|
|
||||||
},
|
|
||||||
Total: '432 (0.22/s)'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, the reported metrics are scaled and formatted in a user friendly way to allow quick inspection. These are however not appropriate for programmatic processing, so the raw values may be retrieved via an optional flag:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
> debug.metrics(true).p2p.InboundTraffic
|
|
||||||
{
|
|
||||||
AvgRate01Min: 1599.6190029292586,
|
|
||||||
AvgRate05Min: 5367.754506658111,
|
|
||||||
AvgRate15Min: 3761.057607521597,
|
|
||||||
MeanRate: 2907.3919382272857,
|
|
||||||
Total: 5901154
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Monitoring metrics
|
|
||||||
|
|
||||||
Although inspecting metrics via the console is very useful to gain an insight into the internal state of Geth, it falls short of visualizing how these metrics evolve over time, possibly under different circumstances and events. To overcome this limitation, Geth introduces a monitoring tool (`geth monitor`) that periodically queries a node for the requested metrics and plots them on a terminal based UI.
|
|
||||||
|
|
||||||
![Monitoring tool](http://i.imgur.com/Nug0sPG.png)
|
|
||||||
|
|
||||||
Monitoring can be started via:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth monitor [--attach=api-endpoint] metric1 metric2 ... metricN
|
|
||||||
```
|
|
||||||
|
|
||||||
Where a metric may be:
|
|
||||||
* Full canonical metric (e.g. `system/memory/allocs/AvgRate05Min`)
|
|
||||||
* Group of metrics (e.g. `system/memory/allocs` or `system/memory`)
|
|
||||||
* Multiple branching metrics (e.g. `system/memory/allocs,frees/AvgRate01Min`)
|
|
||||||
|
|
||||||
Not yet supported but planned:
|
|
||||||
* Wildcard pattern (e.g. `system/memory/*/AvgRate01Min`)
|
|
||||||
* Exclusion pattern (e.g. `system/memory/allocs/!AvgRate01Min`)
|
|
||||||
|
|
||||||
By default `geth monitor` uses 5 chart rows. This makes comparative charts easy as meters have 5 components, and timers 10 (out of which 5 are throughput and 5 percentiles). For custom layout you can override with `--rows`.
|
|
||||||
|
|
||||||
## Available metrics
|
|
||||||
|
|
||||||
Metrics are a debugging tool, with every developer being free to add, remove or modify them as seen fit. As they can change between commits, the exactly available ones can be queried via `geth monitor` or via `debug.metrics(false)` in the console. A few however may warrant longevity, so feel free to add to the below list if you feel it's worth a more general audience:
|
|
||||||
|
|
||||||
* system/memory/
|
|
||||||
* allocs: number of memory allocations made
|
|
||||||
* frees: number of memory releases made
|
|
||||||
* inuse: memory currently being used
|
|
||||||
* pauses: time spent in the garbage collector
|
|
|
@ -1,199 +0,0 @@
|
||||||
---
|
|
||||||
title: Mobile / Account management
|
|
||||||
---
|
|
||||||
To provide Ethereum integration for your mobile applications, the very first thing you should be interested in doing is account management.
|
|
||||||
|
|
||||||
Although all current leading Ethereum implementations provide account management built in, it is ill advised to keep accounts in any location that is shared between multiple applications and/or multiple people. The same way you do not entrust your ISP (who is after all your gateway into the internet) with your login credentials; you should not entrust an Ethereum node (who is your gateway into the Ethereum network) with your credentials either.
|
|
||||||
|
|
||||||
The proper way to handle user accounts in your mobile applications is to do client side account management, everything self-contained within your own application. This way you can ensure as fine grained (or as coarse) access permissions to the sensitive data as deemed necessary, without relying on any third party application's functionality and/or vulnerabilities.
|
|
||||||
|
|
||||||
To support this, `go-ethereum` provides a simple, yet thorough accounts library that gives you all the tools to do properly secured account management via encrypted keystores and passphrase protected accounts. You can leverage all the security of the `go-ethereum` crypto implementation while at the same time running everything in your own application.
|
|
||||||
|
|
||||||
## Encrypted keystores
|
|
||||||
|
|
||||||
Although handling your users' accounts locally on their own mobile device does provide certain security guarantees, access keys to Ethereum accounts should never lay around in clear-text form. As such, we provide an encrypted keystore that provides the proper security guarantees for you without requiring a thorough understanding from your part of the associated cryptographic primitives.
|
|
||||||
|
|
||||||
The important thing to know when using the encrypted keystore is that the cryptographic primitives used within can operate either in *standard* or *light* mode. The former provides a higher level of security at the cost of increased computational burden and resource consumption:
|
|
||||||
|
|
||||||
* *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
|
|
||||||
|
|
||||||
As such, *light* is more suitable for mobile applications, but you should be aware of the trade-offs nonetheless.
|
|
||||||
|
|
||||||
*For those interested in the cryptographic and/or implementation details, the key-store uses the `secp256k1` elliptic curve as defined in the [Standards for Efficient Cryptography](http://www.secg.org/sec2-v2.pdf), implemented by the [`libsecp256k`](https://github.com/bitcoin-core/secp256k1) library and wrapped by [`github.com/ethereum/go-ethereum/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.*
|
|
||||||
|
|
||||||
### Keystores on Android (Java)
|
|
||||||
|
|
||||||
The encrypted keystore on Android is implemented by the `KeyStore` class from the `org.ethereum.geth` package. The configuration constants (for the *standard* or *light* security modes described above) are located in the `Geth` abstract class, similarly from the `org.ethereum.geth` package. Hence to do client side account management on Android, you'll need to import two classes into your Java code:
|
|
||||||
|
|
||||||
```java
|
|
||||||
import org.ethereum.geth.Geth;
|
|
||||||
import org.ethereum.geth.KeyStore;
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards you can create a new encrypted keystore via:
|
|
||||||
|
|
||||||
```java
|
|
||||||
KeyStore ks = new KeyStore("/path/to/keystore", Geth.LightScryptN, Geth.LightScryptP);
|
|
||||||
```
|
|
||||||
|
|
||||||
The path to the keystore folder needs to be a location that is writable by the local mobile application but non-readable for other installed applications (for security reasons obviously), so we'd recommend placing it inside your app's data directory. If you are creating the `KeyStore` from within a class extending an Android object, you will most probably have access to the `Context.getFilesDir()` method via `this.getFilesDir()`, so you could set the keystore path 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. You can choose between `Geth.StandardScryptN, Geth.StandardScryptP`, `Geth.LightScryptN, Geth.LightScryptP` or specify your own numbers (please make sure you understand the underlying cryptography for this). We recommend using the *light* version.
|
|
||||||
|
|
||||||
### Keystores on iOS (Swift 3)
|
|
||||||
|
|
||||||
The encrypted keystore on iOS is implemented by the `GethKeyStore` class from the `Geth` framework. The configuration constants (for the *standard* or *light* security modes described above) are located in the same namespace as global variables. Hence to do client side account management on iOS, you'll need to import the framework into your Swift code:
|
|
||||||
|
|
||||||
```swift
|
|
||||||
import Geth
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards you can create a new encrypted account manager via:
|
|
||||||
|
|
||||||
```swift
|
|
||||||
let ks = GethNewKeyStore("/path/to/keystore", GethLightScryptN, GethLightScryptP);
|
|
||||||
```
|
|
||||||
|
|
||||||
The path to the keystore folder needs to be a location that is writable by the local mobile application but non-readable for other installed applications (for security reasons obviously), so we'd recommend placing it inside your app's document directory. You should be able to retrieve the document directory via `let datadir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]`, so you could set the keystore path to `datadir + "/keystore"`.
|
|
||||||
|
|
||||||
The last two arguments of the `GethNewKeyStore` factory method are the crypto parameters defining how resource-intensive the keystore encryption should be. You can choose between `GethStandardScryptN, GethStandardScryptP`, `GethLightScryptN, GethLightScryptP` or specify your own numbers (please make sure you understand the underlying cryptography for this). We recommend using the *light* version.
|
|
||||||
|
|
||||||
## Account lifecycle
|
|
||||||
|
|
||||||
Having created an encrypted keystore for your Ethereum accounts, you can use this for the entire account lifecycle requirements of your mobile application. This includes the basic functionality of creating new accounts and deleting existing ones; as well as the more advanced functionality of updating access credentials, exporting existing accounts, and importing them on another device.
|
|
||||||
|
|
||||||
Although the keystore defines the encryption strength it uses to store your 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 however 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 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 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 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 we already have an instance of a `KeyStore` called `ks` from the previous section, we can easily execute all of the described lifecycle operations 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 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 we already have an instance of a `GethKeyStore` called `ks` from the previous section, we can easily execute all of the described lifecycle operations 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 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, but 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, 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 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 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. device left unattended; application running untrusted code).
|
|
||||||
|
|
||||||
*Note, creating transactions is out of scope here, so the remainder of this section will assume we already have a transaction to sign, and will focus only on creating an authorized version of it. Creating an actually meaningful transaction will be covered later.*
|
|
||||||
|
|
||||||
### Signing on Android (Java)
|
|
||||||
|
|
||||||
Assuming we already have an instance of a `KeyStore` called `ks` from the previous sections, we can create a new account to sign transactions with via it's already demonstrated `newAccount` method; and to avoid going into transaction creation for now, we can hard-code a random transaction to sign instead.
|
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
With the boilerplate out of the way, we can now sign transaction 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 we already have an instance of a `GethKeyStore` called `ks` from the previous sections, we can create a new account to sign transactions with via it's already demonstrated `newAccount` method; and to avoid going into transaction creation for now, we can hard-code a random transaction to sign instead.
|
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
*Note, although Swift usually rewrites `NSError` returns to throws, this particular instance seems to have been missed for some reason (possibly due to it being a constructor). It will be fixed in a later version of the iOS bindings when the appropriate fixed are implemented upstream in the `gomobile` project.*
|
|
||||||
|
|
||||||
With the boilerplate out of the way, we can now sign transaction 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)
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
---
|
|
||||||
title: Mobile / Introduction
|
|
||||||
---
|
|
||||||
The Ethereum blockchain along with its two extension protocols Whisper and Swarm was originally conceptualized to become the supporting pillar of web3, providing the consensus, messaging and storage backbone for a new generation of distributed (actually, decentralized) applications called DApps.
|
|
||||||
|
|
||||||
The first incarnation towards this dream of web3 was a command line client providing an RPC interface into the peer-to-peer protocols. The client was soon enough extended with a web-browser-like graphical user interface, permitting developers to write DApps based on the tried and proven HTML/CSS/JS technologies.
|
|
||||||
|
|
||||||
As many DApps have more complex requirements than what a browser environment can handle, it became apparent that providing programmatic access to the web3 pillars would open the door towards a new class of applications. As such, the second incarnation of the web3 dream is to open up all our technologies for other projects as reusable components.
|
|
||||||
|
|
||||||
Starting with the 1.5 release family of `go-ethereum`, we transitioned away from providing only a full blown Ethereum client and started shipping official Go packages that could be embedded into third party desktop and server applications. It took only a small leap from here to begin porting our code to mobile platforms.
|
|
||||||
|
|
||||||
## Quick overview
|
|
||||||
|
|
||||||
Similarly to our reusable Go libraries, the mobile wrappers also focus on four main usage areas:
|
|
||||||
|
|
||||||
- Simplified client side account management
|
|
||||||
- Remote node interfacing via different transports
|
|
||||||
- Contract interactions through auto-generated bindings
|
|
||||||
- In-process Ethereum, Whisper and Swarm peer-to-peer node
|
|
||||||
|
|
||||||
You can watch a quick overview about these in Peter's (@karalabe) talk titled "Import Geth: Ethereum from Go and beyond", presented at the Ethereum Devcon2 developer conference in September, 2016 (Shanghai). Slides are [available here](https://ethereum.karalabe.com/talks/2016-devcon.html).
|
|
||||||
|
|
||||||
[![Peter's Devcon2 talk](https://img.youtube.com/vi/R0Ia1U9Gxjg/0.jpg)](https://www.youtube.com/watch?v=R0Ia1U9Gxjg)
|
|
||||||
|
|
||||||
## Library bundles
|
|
||||||
|
|
||||||
The `go-ethereum` mobile library is distributed either as an Android `.aar` archive (containing binaries for `arm-7`, `arm64`, `x86` and `x64`); or as an iOS XCode framework (containing binaries for `arm-7`, `arm64` and `x86`). We do not provide library bundles for Windows phone the moment.
|
|
||||||
|
|
||||||
### Android archive
|
|
||||||
|
|
||||||
The simplest way to use `go-ethereum` in your Android project is through a Maven dependency. We provide bundles of all our stable releases (starting from v1.5.0) through Maven Central, and also provide the latest develop bundle through the Sonatype OSS repository.
|
|
||||||
|
|
||||||
#### Stable dependency (Maven Central)
|
|
||||||
|
|
||||||
To add an Android dependency to the **stable** library release of `go-ethereum`, you'll need to ensure that the Maven Central repository is enabled in your Android project, and that the `go-ethereum` code is listed as a required dependency of your application. You can do both of these by editing the `build.gradle` script in your Android app's folder:
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// All your previous dependencies
|
|
||||||
compile 'org.ethereum:geth:1.5.2' // Change the version to the latest release
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Develop dependency (Sonatype)
|
|
||||||
|
|
||||||
To add an Android dependency to the current **develop** version of `go-ethereum`, you'll need to ensure that the Sonatype snapshot repository is enabled in your Android project, and that the `go-ethereum` code is listed as a required `SNAPSHOT` dependency of your application. You can do both of these by editing the `build.gradle` script in your Android app's folder:
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "https://oss.sonatype.org/content/groups/public"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// All your previous dependencies
|
|
||||||
compile 'org.ethereum:geth:1.5.3-SNAPSHOT' // Change the version to the latest release
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Custom dependency
|
|
||||||
|
|
||||||
If you prefer not to depend on Maven Central or Sonatype; or would like to access an older develop build not available any more as an online dependency, you can download any bundle directly from [our website](https://geth.ethereum.org/downloads/) and insert it into your project in Android Studio via `File -> New -> New module... -> Import .JAR/.AAR Package`.
|
|
||||||
|
|
||||||
You will also need to configure `gradle` to link the mobile library bundle to your application. This can be done by adding a new entry to the `dependencies` section of your `build.gradle` script, pointing it to the module you just added (named `geth` by default).
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
dependencies {
|
|
||||||
// All your previous dependencies
|
|
||||||
compile project(':geth')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Manual builds
|
|
||||||
|
|
||||||
Lastly, if you would like to make modifications to the `go-ethereum` mobile code and/or build it yourself locally instead of downloading a pre-built bundle, you can do so using a `make` command. This will create an Android archive called `geth.aar` in the `build/bin` folder that you can import into your Android Studio as described above.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ make android
|
|
||||||
[...]
|
|
||||||
Done building.
|
|
||||||
Import "build/bin/geth.aar" to use the library.
|
|
||||||
```
|
|
||||||
|
|
||||||
### iOS framework
|
|
||||||
|
|
||||||
The simplest way to use `go-ethereum` in your iOS project is through a [CocoaPods](https://cocoapods.org/) dependency. We provide bundles of all our stable releases (starting from v1.5.3) and also latest develop versions.
|
|
||||||
|
|
||||||
#### Automatic dependency
|
|
||||||
|
|
||||||
To add an iOS dependency to the current stable or latest develop version of `go-ethereum`, you'll need to ensure that your iOS XCode project is configured to use CocoaPods. Detailing that is out of scope in this document, but you can find a guide in the upstream [Using CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html) page. Afterwards you can edit your `Podfile` to list `go-ethereum` as a dependency:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
target 'MyApp' do
|
|
||||||
# All your previous dependencies
|
|
||||||
pod 'Geth', '1.5.4' # Change the version to the latest release
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, if you'd like to use the latest develop version, replace the package version `1.5.4` with `~> 1.5.5-unstable` to switch to pre-releases and to always pull in the latest bundle from a particular release family.
|
|
||||||
|
|
||||||
#### Custom dependency
|
|
||||||
|
|
||||||
If you prefer not to depend on CocoaPods; or would like to access an older develop build not available any more as an online dependency, you can download any bundle directly from [our website](https://geth.ethereum.org/downloads/) and insert it into your project in XCode via `Project Settings -> Build Phases -> Link Binary With Libraries`.
|
|
||||||
|
|
||||||
Do not forget to extract the framework from the compressed `.tar.gz` archive. You can do that either using a GUI tool or from the command line via (replace the archive with your downloaded file):
|
|
||||||
|
|
||||||
```
|
|
||||||
tar -zxvf geth-ios-all-1.5.3-unstable-e05d35e6.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Manual builds
|
|
||||||
|
|
||||||
Lastly, if you would like to make modifications to the `go-ethereum` mobile code and/or build it yourself locally instead of downloading a pre-built bundle, you can do so using a `make` command. This will create an iOS XCode framework called `Geth.framework` in the `build/bin` folder that you can import into XCode as described above.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ make ios
|
|
||||||
[...]
|
|
||||||
Done building.
|
|
||||||
Import "build/bin/Geth.framework" to use the library.
|
|
||||||
```
|
|
|
@ -1,122 +0,0 @@
|
||||||
---
|
|
||||||
title: Native / Account management
|
|
||||||
---
|
|
||||||
To provide Ethereum integration for your native applications, the very first thing you should be interested in doing is account management.
|
|
||||||
|
|
||||||
Although all current leading Ethereum implementations provide account management built in, it is ill advised to keep accounts in any location that is shared between multiple applications and/or multiple people. The same way you do not entrust your ISP (who is after all your gateway into the internet) with your login credentials; you should not entrust an Ethereum node (who is your gateway into the Ethereum network) with your credentials either.
|
|
||||||
|
|
||||||
The proper way to handle user accounts in your native applications is to do client side account management, everything self-contained within your own application. This way you can ensure as fine grained (or as coarse) access permissions to the sensitive data as deemed necessary, without relying on any third party application's functionality and/or vulnerabilities.
|
|
||||||
|
|
||||||
To support this, `go-ethereum` provides a simple, yet thorough accounts package that gives you all the tools to do properly secured account management via encrypted keystores and passphrase protected accounts. You can leverage all the security of the `go-ethereum` crypto implementation while at the same time running everything in your own application.
|
|
||||||
|
|
||||||
## Encrypted keystores
|
|
||||||
|
|
||||||
Although handling accounts locally to an application does provide certain security guarantees, access keys to Ethereum accounts should never lay around in clear-text form. As such, we provide an encrypted keystore that provides the proper security guarantees for you without requiring a thorough understanding from your part of the associated cryptographic primitives.
|
|
||||||
|
|
||||||
The important thing to know when using the encrypted keystore is that the cryptographic primitives used within can operate either in *standard* or *light* mode. The former provides a higher level of security at the cost of increased computational burden and resource consumption:
|
|
||||||
|
|
||||||
* *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
|
|
||||||
|
|
||||||
As such, *standard* is more suitable for native applications, but you should be aware of the trade-offs nonetheless in case you you're targeting more resource constrained environments.
|
|
||||||
|
|
||||||
*For those interested in the cryptographic and/or implementation details, the key-store uses the `secp256k1` elliptic curve as defined in the [Standards for Efficient Cryptography](http://www.secg.org/sec2-v2.pdf), implemented by the [`libsecp256k`](https://github.com/bitcoin-core/secp256k1) library and wrapped by [`github.com/ethereum/go-ethereum/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.*
|
|
||||||
|
|
||||||
### Keystores from Go
|
|
||||||
|
|
||||||
The encrypted keystore is implemented by the [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) struct from the [`github.com/ethereum/go-ethereum/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 to do client side account management from Go, you'll need to import only the `accounts` package into your code:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/ethereum/go-ethereum/accounts"
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards you can create a new encrypted account manager via:
|
|
||||||
|
|
||||||
```go
|
|
||||||
am := accounts.NewManager("/path/to/keystore", accounts.StandardScryptN, accounts.StandardScryptP);
|
|
||||||
```
|
|
||||||
|
|
||||||
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 (for security reasons obviously), so we'd recommend placing it either inside your user's home directory or even more locked down for backend applications.
|
|
||||||
|
|
||||||
The last two arguments of [`accounts.NewManager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#NewManager) are the crypto parameters defining how resource-intensive the keystore encryption should be. You can choose between [`accounts.StandardScryptN, accounts.StandardScryptP`, `accounts.LightScryptN, accounts.LightScryptP`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#pkg-constants) or specify your own numbers (please make sure you understand the underlying cryptography for this). We recommend using the *standard* version.
|
|
||||||
|
|
||||||
## Account lifecycle
|
|
||||||
|
|
||||||
Having created an encrypted keystore for your Ethereum accounts, you can use this account manager for the entire account lifecycle requirements of your native application. This includes the basic functionality of creating new accounts and deleting existing ones; as well as the more advanced functionality of updating access credentials, exporting existing accounts, and importing them on another device.
|
|
||||||
|
|
||||||
Although the keystore defines the encryption strength it uses to store your 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 however 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 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 from Go
|
|
||||||
|
|
||||||
An Ethereum account is implemented by the [`accounts.Account`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Account) struct from the [`github.com/ethereum/go-ethereum/accounts`](https://godoc.org/github.com/ethereum/go-ethereum/accounts) package. Assuming we already have an instance of an [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) called `am` from the previous section, we can easily execute all of the described lifecycle operations with a handful of function calls (error handling omitted).
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Create a new account with the specified encryption passphrase.
|
|
||||||
newAcc, _ := am.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.
|
|
||||||
jsonAcc, _ := am.Export(newAcc, "Creation password", "Export password");
|
|
||||||
|
|
||||||
// Update the passphrase on the account created above inside the local keystore.
|
|
||||||
am.Update(newAcc, "Creation password", "Update password");
|
|
||||||
|
|
||||||
// Delete the account updated above from the local keystore.
|
|
||||||
am.Delete(newAcc, "Update password");
|
|
||||||
|
|
||||||
// Import back the account we've exported (and then deleted) above with yet
|
|
||||||
// again a fresh passphrase.
|
|
||||||
impAcc, _ := am.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 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, but 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, 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; 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 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).
|
|
||||||
|
|
||||||
*Note, creating transactions is out of scope here, so the remainder of this section will assume we already have a transaction hash to sign, and will focus only on creating a cryptographic signature authorizing it. Creating an actual transaction and injecting the authorization signature into it will be covered later.*
|
|
||||||
|
|
||||||
### Signing from Go
|
|
||||||
|
|
||||||
Assuming we already have an instance of an [`accounts.Manager`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager) called `am` from the previous sections, we can create a new account to sign transactions with via it's already demonstrated [`NewAccount`](https://godoc.org/github.com/ethereum/go-ethereum/accounts#Manager.NewAccount) method; and to avoid going into transaction creation for now, we can hard-code a random [`common.Hash`](https://godoc.org/github.com/ethereum/go-ethereum/common#Hash) to sign instead.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Create a new account to sign transactions with
|
|
||||||
signer, _ := am.NewAccount("Signer password");
|
|
||||||
txHash := common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
|
|
||||||
```
|
|
||||||
|
|
||||||
With the boilerplate out of the way, we can now sign transaction using the authorization mechanisms described above:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Sign a transaction with a single authorization
|
|
||||||
signature, _ := am.SignWithPassphrase(signer, "Signer password", txHash.Bytes());
|
|
||||||
|
|
||||||
// Sign a transaction with multiple manually cancelled authorizations
|
|
||||||
am.Unlock(signer, "Signer password");
|
|
||||||
signature, _ = am.Sign(signer.Address, txHash.Bytes());
|
|
||||||
am.Lock(signer.Address);
|
|
||||||
|
|
||||||
// Sign a transaction with multiple automatically cancelled authorizations
|
|
||||||
am.TimedUnlock(signer, "Signer password", time.Second);
|
|
||||||
signature, _ = am.Sign(signer.Address, txHash.Bytes());
|
|
||||||
```
|
|
||||||
|
|
||||||
You may wonder why [`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 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.
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
title: Native / Introduction
|
|
||||||
---
|
|
||||||
The Ethereum blockchain along with its two extension protocols Whisper and Swarm was originally conceptualized to become the supporting pillar of web3, providing the consensus, messaging and storage backbone for a new generation of distributed (actually, decentralized) applications called DApps.
|
|
||||||
|
|
||||||
The first incarnation towards this dream of web3 was a command line client providing an RPC interface into the peer-to-peer protocols. The client was soon enough extended with a web-browser-like graphical user interface, permitting developers to write DApps based on the tried and proven HTML/CSS/JS technologies.
|
|
||||||
|
|
||||||
As many DApps have more complex requirements than what a browser environment can handle, it became apparent that providing programmatic access to the web3 pillars would open the door towards a new class of applications. As such, the second incarnation of the web3 dream is to open up all our technologies for other projects as reusable components.
|
|
||||||
|
|
||||||
Starting with the 1.5 release family of `go-ethereum`, we transitioned away from providing only a full blown Ethereum client and started shipping official Go packages that could be embedded into third party desktop and server applications.
|
|
||||||
|
|
||||||
*Note, this guide will assume you are familiar with Go development. It will make no attempts to cover general topics about Go project layouts, import paths or any other standard methodologies. If you are new to Go, consider reading its [getting started guides](https://github.com/golang/go/wiki#getting-started-with-go) first.*
|
|
||||||
|
|
||||||
## Quick overview
|
|
||||||
|
|
||||||
Our reusable Go libraries focus on four main usage areas:
|
|
||||||
|
|
||||||
- Simplified client side account management
|
|
||||||
- Remote node interfacing via different transports
|
|
||||||
- Contract interactions through auto-generated bindings
|
|
||||||
- In-process Ethereum, Whisper and Swarm peer-to-peer node
|
|
||||||
|
|
||||||
You can watch a quick overview about these in Peter's (@karalabe) talk titled "Import Geth: Ethereum from Go and beyond", presented at the Ethereum Devcon2 developer conference in September, 2016 (Shanghai). Slides are [available here](https://ethereum.karalabe.com/talks/2016-devcon.html).
|
|
||||||
|
|
||||||
[![Peter's Devcon2 talk](https://img.youtube.com/vi/R0Ia1U9Gxjg/0.jpg)](https://www.youtube.com/watch?v=R0Ia1U9Gxjg)
|
|
||||||
|
|
||||||
## Go packages
|
|
||||||
|
|
||||||
The `go-ethereum` library is distributed as a collection of standard Go packages straight from our GitHub repository. The packages can be used directly via the official Go toolkit, without needing any third party tools. External dependencies are vendored locally into `vendor`, ensuring both self-containment as well as code stability. If you reuse `go-ethereum` in your own project, please follow these best practices and vendor it yourself too to avoid any accidental API breakages!
|
|
||||||
|
|
||||||
The canonical import path for `go-ethereum` is `github.com/ethereum/go-ethereum`, with all packages residing underneath. Although there are [quite a number](https://godoc.org/github.com/ethereum/go-ethereum#pkg-subdirectories) of them, you'll only need to care about a limited subset, each of which will be properly introduced in their relevant section.
|
|
||||||
|
|
||||||
You can download all our packages via:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go get -d github.com/ethereum/go-ethereum/...
|
|
||||||
```
|
|
||||||
|
|
||||||
You may also need Go's original context package. Although this was moved into the official Go SDK in Go 1.7, `go-ethereum` will depend on the original `golang.org/x/net/context` package until we officially drop support for Go 1.5 and Go 1.6.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go get -u golang.org/x/net/context
|
|
||||||
```
|
|
|
@ -1,161 +0,0 @@
|
||||||
---
|
|
||||||
title: Peer-to-peer
|
|
||||||
---
|
|
||||||
The peer to peer package ([go-ethereum/p2p](https://github.com/ethereum/go-ethereum/tree/develop/p2p)) allows you to rapidly and easily add peer to peer networking to any type of application. The p2p package is set up in a modular structure and extending the p2p with your own additional sub protocols is easy and straight forward.
|
|
||||||
|
|
||||||
Starting the p2p service only requires you setup a `p2p.Server{}` with a few settings:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/ethereum/go-ethereum/crypto"
|
|
||||||
import "github.com/ethereum/go-ethereum/p2p"
|
|
||||||
|
|
||||||
nodekey, _ := crypto.GenerateKey()
|
|
||||||
srv := p2p.Server{
|
|
||||||
MaxPeers: 10,
|
|
||||||
PrivateKey: nodekey,
|
|
||||||
Name: "my node name",
|
|
||||||
ListenAddr: ":30300",
|
|
||||||
Protocols: []p2p.Protocol{},
|
|
||||||
}
|
|
||||||
srv.Start()
|
|
||||||
```
|
|
||||||
|
|
||||||
If we wanted to extend the capabilities of our p2p server we'd need to pass it an additional sub protocol in the `Protocol: []p2p.Protocol{}` array.
|
|
||||||
|
|
||||||
An additional sub protocol that has the ability to respond to the message "foo" with "bar" requires you to setup an `p2p.Protocol{}`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func MyProtocol() p2p.Protocol {
|
|
||||||
return p2p.Protocol{ // 1.
|
|
||||||
Name: "MyProtocol", // 2.
|
|
||||||
Version: 1, // 3.
|
|
||||||
Length: 1, // 4.
|
|
||||||
Run: func(peer *p2p.Peer, ws p2p.MsgReadWriter) error { return nil }, // 5.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. A sub-protocol object in the p2p package is called `Protocol{}`. Each time a peer connects with the capability of handling this type of protocol will use this;
|
|
||||||
2. The name of your protocol to identify the protocol on the network;
|
|
||||||
3. The version of the protocol.
|
|
||||||
4. The amount of messages this protocol relies on. Because the p2p is extendible and thus has the ability to send an arbitrary amount of messages (with a type, which we'll see later) the p2p handler needs to know how much space it needs to reserve for your protocol, this to ensure consensus can be reached between the peers doing a negotiation over the message IDs. Our protocol supports only one; `message` (as you'll see later).
|
|
||||||
5. The main handler of your protocol. We've left this intentionally blank for now. The `peer` variable is the peer connected to you and provides you with some basic information regarding the peer. The `ws` variable which is a reader and a writer allows you to communicate with the peer. If a message is being send to us by that peer the `MsgReadWriter` will handle it and vice versa.
|
|
||||||
|
|
||||||
Lets fill in the blanks and create a somewhat useful peer by allowing it to communicate with another peer:
|
|
||||||
|
|
||||||
```go
|
|
||||||
const messageId = 0 // 1.
|
|
||||||
type Message string // 2.
|
|
||||||
|
|
||||||
func msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
|
|
||||||
for {
|
|
||||||
msg, err := ws.ReadMsg() // 3.
|
|
||||||
if err != nil { // 4.
|
|
||||||
return err // if reading fails return err which will disconnect the peer.
|
|
||||||
}
|
|
||||||
|
|
||||||
var myMessage [1]Message
|
|
||||||
err = msg.Decode(&myMessage) // 5.
|
|
||||||
if err != nil {
|
|
||||||
// handle decode error
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch myMessage[0] {
|
|
||||||
case "foo":
|
|
||||||
err := p2p.SendItems(ws, messageId, "bar") // 6.
|
|
||||||
if err != nil {
|
|
||||||
return err // return (and disconnect) error if writing fails.
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Println("recv:", myMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. The one and only message we know about;
|
|
||||||
2. A typed string we decode in to;
|
|
||||||
3. `ReadMsg` waits on the line until it receives a message, an error or EOF.
|
|
||||||
4. In case of an error during reading it's best to return that error and let the p2p server handle it. This usually results in a disconnect from the peer.
|
|
||||||
5. `msg` contains two fields and a decoding method:
|
|
||||||
* `Code` contains the message id, `Code == messageId` (i.e., 0)
|
|
||||||
* `Payload` the contents of the message.
|
|
||||||
* `Decode(<ptr>)` is a helper method for: take `msg.Payload` and decodes the rest of the message in to the given interface. If it fails it will return an error.
|
|
||||||
6. If the message we decoded was `foo` respond with a `NewMessage` using the `messageId` message identifier and respond with the message `bar`. The `bar` message would be handled in the `default` case in the same switch.
|
|
||||||
|
|
||||||
Now if we'd tie this all up we'd have a working p2p server with a message passing sub protocol.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
)
|
|
||||||
|
|
||||||
const messageId = 0
|
|
||||||
|
|
||||||
type Message string
|
|
||||||
|
|
||||||
func MyProtocol() p2p.Protocol {
|
|
||||||
return p2p.Protocol{
|
|
||||||
Name: "MyProtocol",
|
|
||||||
Version: 1,
|
|
||||||
Length: 1,
|
|
||||||
Run: msgHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
nodekey, _ := crypto.GenerateKey()
|
|
||||||
srv := p2p.Server{
|
|
||||||
MaxPeers: 10,
|
|
||||||
PrivateKey: nodekey,
|
|
||||||
Name: "my node name",
|
|
||||||
ListenAddr: ":30300",
|
|
||||||
Protocols: []p2p.Protocol{MyProtocol()},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := srv.Start(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {}
|
|
||||||
}
|
|
||||||
|
|
||||||
func msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
|
|
||||||
for {
|
|
||||||
msg, err := ws.ReadMsg()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var myMessage Message
|
|
||||||
err = msg.Decode(&myMessage)
|
|
||||||
if err != nil {
|
|
||||||
// handle decode error
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch myMessage {
|
|
||||||
case "foo":
|
|
||||||
err := p2p.SendItems(ws, messageId, "bar"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Println("recv:", myMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
---
|
|
||||||
title: Private network
|
|
||||||
---
|
|
||||||
An Ethereum network is a private network if the nodes are not connected to the main
|
|
||||||
network nodes. In this context private only means reserved or isolated, rather than
|
|
||||||
protected or secure.
|
|
||||||
|
|
||||||
## Choosing A Network ID
|
|
||||||
|
|
||||||
Since connections between nodes are valid only if peers have identical protocol version
|
|
||||||
and network ID, you can effectively isolate your network by setting either of these to a
|
|
||||||
non default value. We recommend using the `--networkid` command line option for this. Its
|
|
||||||
argument is an integer, the main network has id 1 (the default). So if you supply your own
|
|
||||||
custom network ID which is different than the main network your nodes will not connect to
|
|
||||||
other nodes and form a private network.
|
|
||||||
|
|
||||||
## Creating The Genesis Block
|
|
||||||
|
|
||||||
Every blockchain starts with the genesis block. When you run geth with default settings
|
|
||||||
for the first time, the main net genesis block is committed to the database. For a private
|
|
||||||
network, you usually want a different genesis block.
|
|
||||||
|
|
||||||
Here's an example of a custom genesis.json file. The `config` section ensures that certain
|
|
||||||
protocol upgrades are immediately available. The `alloc` section pre-funds accounts.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"config": {
|
|
||||||
"chainId": 15,
|
|
||||||
"homesteadBlock": 0,
|
|
||||||
"eip155Block": 0,
|
|
||||||
"eip158Block": 0
|
|
||||||
},
|
|
||||||
"difficulty": "200000000",
|
|
||||||
"gasLimit": "2100000",
|
|
||||||
"alloc": {
|
|
||||||
"7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000" },
|
|
||||||
"f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To create a database that uses this genesis block, run the following command. This will
|
|
||||||
import and set the canonical genesis block for your chain.
|
|
||||||
|
|
||||||
```text
|
|
||||||
geth --datadir path/to/custom/data/folder init genesis.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Future runs of geth on this data directory will use the genesis block you have defined.
|
|
||||||
|
|
||||||
```text
|
|
||||||
geth --datadir path/to/custom/data/folder --networkid 15
|
|
||||||
```
|
|
||||||
|
|
||||||
## Network Connectivity
|
|
||||||
|
|
||||||
With all nodes that you want to run initialized to the desired genesis state, you'll need
|
|
||||||
to start a bootstrap node that others can use to find each other in your network and/or
|
|
||||||
over the internet. The clean way is to configure and run a dedicated bootnode:
|
|
||||||
|
|
||||||
```text
|
|
||||||
bootnode --genkey=boot.key
|
|
||||||
bootnode --nodekey=boot.key
|
|
||||||
```
|
|
||||||
|
|
||||||
With the bootnode online, it will display an enode URL that other nodes can use to connect
|
|
||||||
to it and exchange peer information. Make sure to replace the displayed IP address
|
|
||||||
information (most probably [::]) with your externally accessible IP to get the actual
|
|
||||||
enode URL.
|
|
||||||
|
|
||||||
Note: You can also use a full fledged Geth node as a bootstrap node.
|
|
||||||
|
|
||||||
### Starting Up Your Member Nodes
|
|
||||||
|
|
||||||
With the bootnode operational and externally reachable (you can try `telnet <ip> <port>`
|
|
||||||
to ensure it's indeed reachable), start every subsequent Geth node pointed to the bootnode
|
|
||||||
for peer discovery via the --bootnodes flag. It will probably also be desirable to keep
|
|
||||||
the data directory of your private network separated, so do also specify a custom
|
|
||||||
`--datadir` flag.
|
|
||||||
|
|
||||||
```text
|
|
||||||
geth --datadir path/to/custom/data/folder --networkid 15 --bootnodes <bootnode-enode-url-from-above>
|
|
||||||
```
|
|
||||||
|
|
||||||
Since your network will be completely cut off from the main and test networks, you'll also
|
|
||||||
need to configure a miner to process transactions and create new blocks for you.
|
|
||||||
|
|
||||||
## Running A Private Miner
|
|
||||||
|
|
||||||
Mining on the public Ethereum network is a complex task as it's only feasible using GPUs,
|
|
||||||
requiring an OpenCL or CUDA enabled ethminer instance. For information on such a setup,
|
|
||||||
please consult the EtherMining subreddit and the Genoil miner repository.
|
|
||||||
|
|
||||||
In a private network setting however, a single CPU miner instance is more than enough for
|
|
||||||
practical purposes as it can produce a stable stream of blocks at the correct intervals
|
|
||||||
without needing heavy resources (consider running on a single thread, no need for multiple
|
|
||||||
ones either). To start a Geth instance for mining, run it with all your usual flags,
|
|
||||||
extended by:
|
|
||||||
|
|
||||||
```text
|
|
||||||
$ geth <usual-flags> --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
|
|
||||||
```
|
|
||||||
|
|
||||||
Which will start mining bocks and transactions on a single CPU thread, crediting all
|
|
||||||
proceedings to the account specified by --etherbase. You can further tune the mining by
|
|
||||||
changing the default gas limit blocks converge to (`--targetgaslimit`) and the price
|
|
||||||
transactions are accepted at (`--gasprice`).
|
|
|
@ -1,45 +0,0 @@
|
||||||
---
|
|
||||||
title: Provisional JS API
|
|
||||||
---
|
|
||||||
The *provisional* JavaScript API is a purposed API for all things JavaScript. JavaScript technologies can be embedded within Qt(QML) technologies, local web and remote web and therefor the purposed API is written in a ASYNC fashion so that it may be used across all implementations. Hereby it should be known that all functions, unless explicitly specified, take a callback as last function argument which will be called when the operation has been completed.
|
|
||||||
|
|
||||||
Please note that the provisional JavaScript API tries to leverage existing JS idioms as much as possible.
|
|
||||||
|
|
||||||
## General API
|
|
||||||
|
|
||||||
* `getBlock (number or string)`
|
|
||||||
Retrieves a block by either the address or the number. If supplied with a string it will assume address, number otherwise.
|
|
||||||
* `transact (sec, recipient, value, gas, gas price, data)`
|
|
||||||
Creates a new transaction using your current key.
|
|
||||||
* `create (sec, value, gas, gas price, init, body)`
|
|
||||||
Creates a new contract using your current key.
|
|
||||||
* `getKey (none)`
|
|
||||||
Retrieves your current key in hex format.
|
|
||||||
* `getStorage (object address, storage address)`
|
|
||||||
Retrieves the storage address of the given object.
|
|
||||||
* `getBalance (object address)`
|
|
||||||
Retrieves the balance at the current address
|
|
||||||
* `watch (string [, string])`
|
|
||||||
Watches for changes on a specific address' state object such as state root changes or value changes.
|
|
||||||
* `disconnect (string [, string])`
|
|
||||||
Disconnects from a previous `watched` address.
|
|
||||||
|
|
||||||
## Events
|
|
||||||
|
|
||||||
The provisional JavaScript API exposes certain events through a basic eventing mechanism inspired by jQuery.
|
|
||||||
|
|
||||||
* `on (event)`
|
|
||||||
Subscribe to event which will be called whenever an event of type <event> is received.
|
|
||||||
* `off (event)`
|
|
||||||
Unsubscribe to the given event
|
|
||||||
* `trigger (event, data)`
|
|
||||||
Trigger event of type <event> with the given data. **note:** This function does not take a callback function.
|
|
||||||
|
|
||||||
### Event Types
|
|
||||||
|
|
||||||
All events are written in camel cased style beginning with a lowercase letter. Subevents are denoted by a colon `:`.
|
|
||||||
|
|
||||||
* `block:new`
|
|
||||||
Fired when a new valid block has been found on the wire. The attached value of this call is a block.
|
|
||||||
* `object:changed`
|
|
||||||
Fired when a watched address, specified through `watch`, changes in value.
|
|
|
@ -1,145 +0,0 @@
|
||||||
---
|
|
||||||
title: RPS pub-sub
|
|
||||||
---
|
|
||||||
# Introduction
|
|
||||||
|
|
||||||
From version 1.4 geth has **_experimental_** support for pub/sub using subscriptions as defined in the JSON-RPC 2.0 specification. This allows clients to wait for events instead of polling for them.
|
|
||||||
|
|
||||||
It works by subscribing to particular events. The node will return a subscription id. For each event that matches the subscription a notification with relevant data is send together with the subscription id.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
// create subscription
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["newHeads", {}]}
|
|
||||||
<< {"jsonrpc":"2.0","id":1,"result":"0xcd0c3e8af590364c09d0fa6a1210faf5"}
|
|
||||||
|
|
||||||
// incoming notifications
|
|
||||||
<< {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0xcd0c3e8af590364c09d0fa6a1210faf5","result":{"difficulty":"0xd9263f42a87",<...>, "uncles":[]}}}
|
|
||||||
<< {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0xcd0c3e8af590364c09d0fa6a1210faf5","result":{"difficulty":"0xd90b1a7ad02", <...>, "uncles":["0x80aacd1ea4c9da32efd8c2cc9ab38f8f70578fcd46a1a4ed73f82f3e0957f936"]}}}
|
|
||||||
|
|
||||||
// cancel subscription
|
|
||||||
>> {"id": 1, "method": "eth_unsubscribe", "params": ["0xcd0c3e8af590364c09d0fa6a1210faf5"]}
|
|
||||||
<< {"jsonrpc":"2.0","id":1,"result":true}
|
|
||||||
|
|
||||||
# Considerations
|
|
||||||
1. notifications are send for current events and not for past events. If your use case requires you not to miss any notifications than subscriptions are probably not the best option.
|
|
||||||
2. subscriptions require a full duplex connection. Geth offers such connections in the form of websockets (enable with --ws) and ipc (enabled by default).
|
|
||||||
3. subscriptions are coupled to a connection. If the connection is closed all subscriptions that are created over this connection are removed.
|
|
||||||
4. notifications are stored in an internal buffer and sent from this buffer to the client. If the client is unable to keep up and the number of buffered notifications reaches a limit (currently 10k) the connection is closed. Keep in mind that subscribing to some events can cause a flood of notifications, e.g. listening for all logs/blocks when the node starts to synchronize.
|
|
||||||
|
|
||||||
## Create subscription
|
|
||||||
Subscriptions are creates with a regular RPC call with `eth_subscribe` as method and the subscription name as first parameter. If successful it returns the subscription id.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
1. subscription name
|
|
||||||
2. optional arguments
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["newHeads", {"includeTransactions": true}]}
|
|
||||||
<< {"id": 1, "jsonrpc": "2.0", "result": "0x9cef478923ff08bf67fde6c64013158d"}
|
|
||||||
|
|
||||||
## Cancel subscription
|
|
||||||
Subscriptions are cancelled with a regular RPC call with `eth_unsubscribe` as method and the subscription id as first parameter. It returns a bool indicating if the subscription was cancelled successful.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
1. subscription id
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
>> {"id": 1, "method": "eth_unsubscribe", "params": ["0x9cef478923ff08bf67fde6c64013158d"]}
|
|
||||||
<< {"jsonrpc":"2.0","id":1,"result":true}
|
|
||||||
|
|
||||||
# Supported subscriptions
|
|
||||||
|
|
||||||
## newHeads
|
|
||||||
Fires a notification each time a new header is appended to the chain, including chain reorganizations. Users can use the bloom filter to determine if the block contains logs that are interested to them.
|
|
||||||
|
|
||||||
In case of a chain reorganization the subscription will emit all new headers for the new chain. Therefore the subscription can emit multiple headers on the same height.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["newHeads"]}
|
|
||||||
<< {"jsonrpc":"2.0","id":2,"result":"0x9ce59a13059e417087c02d3236a0b1cc"}
|
|
||||||
|
|
||||||
<< {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "eth_subscription",
|
|
||||||
"params": {
|
|
||||||
"result": {
|
|
||||||
"difficulty": "0x15d9223a23aa",
|
|
||||||
"extraData": "0xd983010305844765746887676f312e342e328777696e646f7773",
|
|
||||||
"gasLimit": "0x47e7c4",
|
|
||||||
"gasUsed": "0x38658",
|
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069",
|
|
||||||
"nonce": "0x084149998194cc5f",
|
|
||||||
"number": "0x1348c9",
|
|
||||||
"parentHash": "0x7736fab79e05dc611604d22470dadad26f56fe494421b5b333de816ce1f25701",
|
|
||||||
"receiptRoot": "0x2fab35823ad00c7bb388595cb46652fe7886e00660a01e867824d3dceb1c8d36",
|
|
||||||
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
|
||||||
"stateRoot": "0xb3346685172db67de536d8765c43c31009d0eb3bd9c501c9be3229203f15f378",
|
|
||||||
"timestamp": "0x56ffeff8",
|
|
||||||
"transactionsRoot": "0x0167ffa60e3ebc0b080cdb95f7c0087dd6c0e61413140e39d94d3468d7c9689f"
|
|
||||||
},
|
|
||||||
"subscription": "0x9ce59a13059e417087c02d3236a0b1cc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## logs
|
|
||||||
Returns logs that are included in new imported blocks and match the given filter criteria.
|
|
||||||
|
|
||||||
In case of a chain reorganization previous sent logs that are on the old chain will be resend with the `removed` property set to true. Logs from transactions that ended up in the new chain are emitted. Therefore a subscription can emit logs for the same transaction multiple times.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
1. `object` with the following (optional) fields
|
|
||||||
- **address**, either an address or an array of addresses. Only logs that are created from these addresses are returned (optional)
|
|
||||||
- **topics**, only logs which match the specified topics (optional)
|
|
||||||
|
|
||||||
|
|
||||||
### Example
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["logs", {"address": "0x8320fe7702b96808f7bbc0d4a888ed1468216cfd", "topics": ["0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902"]}]}
|
|
||||||
<< {"jsonrpc":"2.0","id":2,"result":"0x4a8a4c0517381924f9838102c5a4dcb7"}
|
|
||||||
|
|
||||||
<< {"jsonrpc":"2.0","method":"eth_subscription","params": {"subscription":"0x4a8a4c0517381924f9838102c5a4dcb7","result":{"address":"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd","blockHash":"0x61cdb2a09ab99abf791d474f20c2ea89bf8de2923a2d42bb49944c8c993cbf04","blockNumber":"0x29e87","data":"0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003","logIndex":"0x0","topics":["0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902"],"transactionHash":"0xe044554a0a55067caafd07f8020ab9f2af60bdfe337e395ecd84b4877a3d1ab4","transactionIndex":"0x0"}}}
|
|
||||||
|
|
||||||
## newPendingTransactions
|
|
||||||
Returns the hash for all transactions that are added to the pending state and are signed with a key that is available in the node.
|
|
||||||
|
|
||||||
When a transaction that was previously part of the canonical chain isn't part of the new canonical chain after a reogranization its again emitted.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
none
|
|
||||||
|
|
||||||
### Example
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]}
|
|
||||||
<< {"jsonrpc":"2.0","id":2,"result":"0xc3b33aa549fb9a60e95d21862596617c"}
|
|
||||||
|
|
||||||
<< {
|
|
||||||
"jsonrpc":"2.0",
|
|
||||||
"method":"eth_subscription",
|
|
||||||
"params":{
|
|
||||||
"subscription":"0xc3b33aa549fb9a60e95d21862596617c",
|
|
||||||
"result":"0xd6fdc5cc41a9959e922f30cb772a9aef46f4daea279307bc5f7024edc4ccd7fa"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## syncing
|
|
||||||
Indicates when the node starts or stops synchronizing. The result can either be a boolean indicating that the synchronization has started (true), finished (false) or an object with various progress indicators.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
none
|
|
||||||
|
|
||||||
### Example
|
|
||||||
>> {"id": 1, "method": "eth_subscribe", "params": ["syncing"]}
|
|
||||||
<< {"jsonrpc":"2.0","id":2,"result":"0xe2ffeb2703bcf602d42922385829ce96"}
|
|
||||||
|
|
||||||
<< {"subscription":"0xe2ffeb2703bcf602d42922385829ce96","result":{"syncing":true,"status":{"startingBlock":674427,"currentBlock":67400,"highestBlock":674432,"pulledStates":0,"knownStates":0}}}}
|
|
||||||
|
|
||||||
|
|
||||||
## Possible future subscription:
|
|
||||||
- balance changes
|
|
||||||
- account changes
|
|
||||||
- nonce changes
|
|
||||||
- storage changes in contracts
|
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
title: Running in Docker
|
|
||||||
---
|
|
||||||
|
|
||||||
We keep a Docker image with recent snapshot builds from the `develop` branch [on DockerHub](https://hub.docker.com/r/ethereum/client-go/). In addition to the container based on [Ubuntu](http://www.ubuntu.com) (158 MB), there is a smaller image using [Alpine Linux](https://alpinelinux.org) (35 MB). To use the alpine [tag](https://hub.docker.com/r/ethereum/client-go/tags), replace `ethereum/client-go` with `ethereum/client-go:alpine` in the examples below.
|
|
||||||
|
|
||||||
To pull the image, run this command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker pull ethereum/client-go
|
|
||||||
```
|
|
||||||
|
|
||||||
Start a node with:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -it -p 30303:30303 ethereum/client-go
|
|
||||||
```
|
|
||||||
|
|
||||||
To start a node that runs the JSON-RPC interface on port **8545**, run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -it -p 8545:8545 -p 30303:30303 ethereum/client-go --rpc --rpcaddr "0.0.0.0"
|
|
||||||
```
|
|
||||||
**WARNING: This opens your container to external calls. "0.0.0.0" should _not_ be used when exposed to public networks**
|
|
||||||
|
|
||||||
To use the interactive JavaScript console, run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker run -it -p 30303:30303 ethereum/client-go console
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using Data Volumes
|
|
||||||
|
|
||||||
To persist downloaded blockchain data between container starts, use Docker [data volumes](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-host-directory-as-a-data-volume). Replace `/path/on/host` with the location you want to store the data in.
|
|
||||||
|
|
||||||
docker run -it -p 30303:30303 -v /path/on/host:/root/.ethereum ethereum/client-go
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
title: Sending ether
|
|
||||||
---
|
|
||||||
|
|
||||||
The basic way of sending a simple transaction of ether with the console is as follows:
|
|
||||||
```js
|
|
||||||
> eth.sendTransaction({from:sender, to:receiver, value: amount})
|
|
||||||
```
|
|
||||||
|
|
||||||
Using the built-in JavaScript, you can easily set variables to hold these values. For example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> var sender = eth.accounts[0];
|
|
||||||
> var receiver = eth.accounts[1];
|
|
||||||
> var amount = web3.toWei(0.01, "ether")
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can compose a transaction in a single line with:
|
|
||||||
|
|
||||||
```js
|
|
||||||
> eth.sendTransaction({from:eth.coinbase, to:eth.accounts[1], value: web3.toWei(0.05, "ether")})
|
|
||||||
Please unlock account d1ade25ccd3d550a7eb532ac759cac7be09c2719.
|
|
||||||
Passphrase:
|
|
||||||
Account is now unlocked for this session.
|
|
||||||
'0xeeb66b211e7d9be55232ed70c2ebb1bcc5d5fd9ed01d876fac5cff45b5bf8bf4'
|
|
||||||
```
|
|
||||||
|
|
||||||
The resulting transaction is `0xeeb66b211e7d9be55232ed70c2ebb1bcc5d5fd9ed01d876fac5cff45b5bf8bf4`
|
|
||||||
|
|
||||||
If the password was incorrect you will instead receive an error:
|
|
||||||
```js
|
|
||||||
error: could not unlock sender account
|
|
||||||
```
|
|
|
@ -1,28 +0,0 @@
|
||||||
---
|
|
||||||
title: Setting up Ethereum Native
|
|
||||||
---
|
|
||||||
## Dream API
|
|
||||||
|
|
||||||
i.e., something I'm envisioning for *soon*(tm)
|
|
||||||
|
|
||||||
```go
|
|
||||||
eth, err := eth.New(/*config*/)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// State holds accounts without matching private keys
|
|
||||||
state := eth.State()
|
|
||||||
// wallet holds accounts with matching private keys
|
|
||||||
wallet := eth.Wallet()
|
|
||||||
wallet.NewAccount() // create a new account (return Account)
|
|
||||||
wallet.Accounts() // return []Account
|
|
||||||
|
|
||||||
acc := wallet.GetAcccount(0) // Get first account (return Account)
|
|
||||||
to := state.GetAccount(toAddr)
|
|
||||||
// Transact from the account
|
|
||||||
err := acc.Transact(to, big(100), big(10000), big(500), big(util.DefaultGasPrice), nil)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalln(err)
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,57 +0,0 @@
|
||||||
---
|
|
||||||
title: Setting up monitoring on local cluster
|
|
||||||
---
|
|
||||||
This page describes how to set up a monitoring site, [like this one](http://eth-netstats.herokuapp.com/), for your private network. It builds upon [this wiki article](Setting-up-private-network-or-local-cluster) and assumes you've created a local cluster using [this script (gethcluster.sh)](https://github.com/ethersphere/eth-utils).
|
|
||||||
|
|
||||||
The monitoring system consists of two components:
|
|
||||||
|
|
||||||
1. **eth-netstats** - the monitoring site which lists the nodes.
|
|
||||||
2. **eth-net-intelligence-api** - these are processes that communicate with the ethereum client using RPC and push the data to the monitoring site via websockets.
|
|
||||||
|
|
||||||
#Monitoring site
|
|
||||||
Clone the repo and install dependencies:
|
|
||||||
|
|
||||||
git clone https://github.com/cubedro/eth-netstats
|
|
||||||
cd eth-netstats
|
|
||||||
npm install
|
|
||||||
|
|
||||||
Then choose a secret and start the app:
|
|
||||||
|
|
||||||
WS_SECRET=<chosen_secret> npm start
|
|
||||||
|
|
||||||
You can now access the (empty) monitoring site at `http://localhost:3000`.
|
|
||||||
|
|
||||||
You can also choose a different port:
|
|
||||||
|
|
||||||
PORT=<chosen_port> WS_SECRET=<chosen_secret> npm start
|
|
||||||
|
|
||||||
#Client-side information relays
|
|
||||||
These processes will relay the information from each of your cluster nodes to the monitoring site using websockets.
|
|
||||||
|
|
||||||
Clone the repo, install dependencies and make sure you have pm2 installed:
|
|
||||||
|
|
||||||
git clone https://github.com/cubedro/eth-net-intelligence-api
|
|
||||||
cd eth-net-intelligence-api
|
|
||||||
npm install
|
|
||||||
sudo npm install -g pm2
|
|
||||||
|
|
||||||
Now, use [this script (netstatconf.sh)](https://github.com/ethersphere/eth-utils) to create an `app.json` suitable for pm2.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
bash netstatconf.sh <number_of_clusters> <name_prefix> <ws_server> <ws_secret>
|
|
||||||
|
|
||||||
- `number_of_clusters` is the number of nodes in the cluster.
|
|
||||||
- `name_prefix` is a prefix for the node names as will appear in the listing.
|
|
||||||
- `ws_server` is the eth-netstats server. Make sure you write the full URL, for example: http://localhost:3000.
|
|
||||||
- `ws_secret` is the eth-netstats secret.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
bash netstatconf.sh 5 mynode http://localhost:3000 big-secret > app.json
|
|
||||||
|
|
||||||
Run the script and copy the resulting `app.json` into the `eth-net-intelligence-api` directory. Afterwards, `cd` into `eth-net-intelligence-api` and run the relays using `pm2 start app.json`. To stop the relays, you can use `pm2 delete app.json`.
|
|
||||||
|
|
||||||
**NOTE**: The script assumes the nodes have RPC ports 8101, 8102, ... . If that's not the case, edit app.json and change it accordingly for each peer.
|
|
||||||
|
|
||||||
At this point, open `http://localhost:3000` and your monitoring site should monitor all your nodes!
|
|
|
@ -1,119 +0,0 @@
|
||||||
---
|
|
||||||
title: Setting up private network or local cluster
|
|
||||||
---
|
|
||||||
This page describes how to set up a local cluster of nodes, advise how to make it private, and how to hook up your nodes on the eth-netstat network monitoring app.
|
|
||||||
A fully controlled ethereum network is useful as a backend for network integration testing (core developers working on issues related to networking/blockchain synching/message propagation, etc or DAPP developers testing multi-block and multi-user scenarios).
|
|
||||||
|
|
||||||
We assume you are able to build `geth` following the [build instructions](../install-and-build/Building-Ethereum)
|
|
||||||
|
|
||||||
## Setting up multiple nodes
|
|
||||||
|
|
||||||
In order to run multiple ethereum nodes locally, you have to make sure:
|
|
||||||
- each instance has a separate data directory (`--datadir`)
|
|
||||||
- each instance runs on a different port (both eth and rpc) (`--port and --rpcport`)
|
|
||||||
- in case of a cluster the instances must know about each other
|
|
||||||
- the ipc endpoint is unique or the ipc interface is disabled (`--ipcpath or --ipcdisable`)
|
|
||||||
|
|
||||||
You start the first node (let's make port explicit and disable ipc interface)
|
|
||||||
```bash
|
|
||||||
geth --datadir="/tmp/eth/60/01" -verbosity 6 --ipcdisable --port 30301 --rpcport 8101 console 2>> /tmp/eth/60/01.log
|
|
||||||
```
|
|
||||||
|
|
||||||
We started the node with the console, so that we can grab the enode url for instance:
|
|
||||||
|
|
||||||
```
|
|
||||||
> admin.nodeInfo.enode
|
|
||||||
enode://8c544b4a07da02a9ee024def6f3ba24b2747272b64e16ec5dd6b17b55992f8980b77938155169d9d33807e501729ecb42f5c0a61018898c32799ced152e9f0d7@9[::]:30301
|
|
||||||
```
|
|
||||||
|
|
||||||
`[::]` will be parsed as localhost (`127.0.0.1`). If your nodes are on a local network check each individual host machine and find your ip with `ifconfig` (on Linux and MacOS):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ ifconfig|grep netmask|awk '{print $2}'
|
|
||||||
127.0.0.1
|
|
||||||
192.168.1.97
|
|
||||||
```
|
|
||||||
|
|
||||||
If your peers are not on the local network, you need to know your external IP address (use a service) to construct the enode url.
|
|
||||||
|
|
||||||
Now you can launch a second node with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
geth --datadir="/tmp/eth/60/02" --verbosity 6 --ipcdisable --port 30302 --rpcport 8102 console 2>> /tmp/eth/60/02.log
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to connect this instance to the previously started node you can add it as a peer from the console with `admin.addPeer(enodeUrlOfFirstInstance)`.
|
|
||||||
|
|
||||||
You can test the connection by typing in geth console:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
> net.listening
|
|
||||||
true
|
|
||||||
> net.peerCount
|
|
||||||
1
|
|
||||||
> admin.peers
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Local cluster
|
|
||||||
|
|
||||||
As an extention of the above, you can spawn a local cluster of nodes easily. It can also be scripted including account creation which is needed for mining.
|
|
||||||
See [`gethcluster.sh`](https://github.com/ethersphere/eth-utils) script, and the README there for usage and examples.
|
|
||||||
|
|
||||||
## Private network
|
|
||||||
|
|
||||||
See [[the Private Network Page|Private network]] for more information.
|
|
||||||
|
|
||||||
### Setup bootnode
|
|
||||||
|
|
||||||
The first time a node connects to the network it uses one of the predefined [bootnodes](https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go). Through these bootnodes a node can join the network and find other nodes. In the case of a private cluster these predefined bootnodes are not of much use. Therefore go-ethereum offers a bootnode implementation that can be configured and run in your private network.
|
|
||||||
|
|
||||||
It can be run through the command.
|
|
||||||
```
|
|
||||||
> bootnode
|
|
||||||
Fatal: Use -nodekey or -nodekeyhex to specify a private key
|
|
||||||
```
|
|
||||||
|
|
||||||
As can be seen the bootnode asks for a key. Each ethereum node, including a bootnode is identified by an enode identifier. These identifiers are derived from a key. Therefore you will need to give the bootnode such key. Since we currently don't have one we can instruct the bootnode to generate a key (and store it in a file) before it starts.
|
|
||||||
|
|
||||||
```
|
|
||||||
> bootnode -genkey bootnode.key
|
|
||||||
I0216 09:53:08.076155 p2p/discover/udp.go:227] Listening, enode://890b6b5367ef6072455fedbd7a24ebac239d442b18c5ab9d26f58a349dad35ee5783a0dd543e4f454fed22db9772efe28a3ed6f21e75674ef6203e47803da682@[::]:30301
|
|
||||||
```
|
|
||||||
|
|
||||||
(exit with CTRL-C)
|
|
||||||
|
|
||||||
The stored key can be seen with:
|
|
||||||
```
|
|
||||||
> cat bootnode.key
|
|
||||||
dc90f8f7324f1cc7ba52c4077721c939f98a628ed17e51266d01c9cd0294033a
|
|
||||||
```
|
|
||||||
|
|
||||||
To instruct geth nodes to use our own bootnode(s) use the `--bootnodes` flag. This is a comma separated list of bootnode enode identifiers.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --bootnodes "enode://890b6b5367ef6072455fedbd7a24ebac239d442b18c5ab9d26f58a349dad35ee5783a0dd543e4f454fed22db9772efe28a3ed6f21e75674ef6203e47803da682@[::]:30301"
|
|
||||||
```
|
|
||||||
(what [::] means is explained previously)
|
|
||||||
|
|
||||||
Since it is convenient to start the bootnode each time with the same enode we can give the bootnode program the just generated key on the next time it is started.
|
|
||||||
|
|
||||||
```
|
|
||||||
bootnode -nodekey bootnode.key
|
|
||||||
I0216 10:01:19.125600 p2p/discover/udp.go:227] Listening, enode://890b6b5367ef6072455fedbd7a24ebac239d442b18c5ab9d26f58a349dad35ee5783a0dd543e4f454fed22db9772efe28a3ed6f21e75674ef6203e47803da682@[::]:30301
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
bootnode -nodekeyhex dc90f8f7324f1cc7ba52c4077721c939f98a628ed17e51266d01c9cd0294033a
|
|
||||||
I0216 10:01:40.094089 p2p/discover/udp.go:227] Listening, enode://890b6b5367ef6072455fedbd7a24ebac239d442b18c5ab9d26f58a349dad35ee5783a0dd543e4f454fed22db9772efe28a3ed6f21e75674ef6203e47803da682@[::]:30301
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Monitoring your nodes
|
|
||||||
|
|
||||||
[This page](https://github.com/ethereum/wiki/wiki/Network-Status) describes how to use the [The Ethereum (centralised) network status monitor (known sometimes as "eth-netstats")](http://stats.ethdev.com) to monitor your nodes.
|
|
||||||
|
|
||||||
[This page](Setting-up-monitoring-on-local-cluster) or [this README](https://github.com/ethersphere/eth-utils)
|
|
||||||
describes how you set up your own monitoring service for a (private or public) local cluster.
|
|
|
@ -1,80 +0,0 @@
|
||||||
---
|
|
||||||
title: Swarm TODO
|
|
||||||
---
|
|
||||||
# Sprint plan
|
|
||||||
|
|
||||||
# scope
|
|
||||||
- forwarding only (no recursive lookup and no connecting to new nodes, only working with active peers)
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- integrate new p2p
|
|
||||||
- write unit tests for protocol and netstore (without protocol)
|
|
||||||
- rework protocol errors using errs after PR merged
|
|
||||||
- integrate new p2p or develop branch after p2p merge
|
|
||||||
- integrate cademlia into hive / peer pool with new p2p
|
|
||||||
- work out timeouts and timeout encoding
|
|
||||||
- cli tools
|
|
||||||
- url bar and proxy
|
|
||||||
|
|
||||||
## CLI
|
|
||||||
- hooking into DPA local API
|
|
||||||
- running as a daemon accepting request via socket?
|
|
||||||
|
|
||||||
### -
|
|
||||||
## Encryption
|
|
||||||
- encryption gateway to incentivise encryption of public content
|
|
||||||
- xor encryption with random chunks
|
|
||||||
- in-memory encryption keys
|
|
||||||
- originator encryption for private content
|
|
||||||
|
|
||||||
|
|
||||||
## APIs
|
|
||||||
- DAPP API - js integration (Fabian, Alex)
|
|
||||||
- mist dapp storage scheme, url->hash mapping (Fabian, Alex) [URL scheme](URL-Scheme)
|
|
||||||
|
|
||||||
# Discuss alternatives
|
|
||||||
|
|
||||||
I suggest we each pick 2/3 and read up on their project status, features, useability, objectives, etc
|
|
||||||
- Is it even worth it to reinvent/reimplement the wheel?
|
|
||||||
- what features do we want now and in future
|
|
||||||
- roadmap
|
|
||||||
|
|
||||||
# Brainstorming
|
|
||||||
|
|
||||||
- storage economy, incentivisation, examples:
|
|
||||||
-- content owner pays recurring ether fee for storage.
|
|
||||||
-- scheme to reward content owner each time content is accessed. i.e accessing content would requires fee. this would reward popular content. should be optional though.
|
|
||||||
- dht - chain interaction
|
|
||||||
- proof of custody https://docs.google.com/document/d/1F81ulKEZFPIGNEVRsx0H1gl2YRtf0mUMsX011BzSjnY/edit
|
|
||||||
- proof of resources http://systemdocs.maidsafe.net/content/system_components/proof_of_resources.html
|
|
||||||
- nonoutsourceable proofs of storage as mining criteria
|
|
||||||
- proof of storage capacity directly rewarded by contract
|
|
||||||
- streaming, hash chains
|
|
||||||
- routing and learning graph traversal
|
|
||||||
- minimising hops
|
|
||||||
- forwarding strategies, optimising dispersion of requests
|
|
||||||
- lifetime of requests, renewals (repeated retrieval requests), expiry, reposting (repeated storage request)
|
|
||||||
- redundancy - store same data in multiple nodes (e.g 4x)
|
|
||||||
- the more accessed a content is, the more available it should be, should increase performance for popular content.
|
|
||||||
|
|
||||||
# Simulations
|
|
||||||
|
|
||||||
- full table homogeneous nodes network size vs density vs table size expected row-sizes
|
|
||||||
- forwarding strategy vs latency vs traffic
|
|
||||||
- stable table, dropout rate vs routing optimisation by precalculating subtables for all peers. expected distance change (proximity delta) per hop
|
|
||||||
|
|
||||||
|
|
||||||
## Swarm
|
|
||||||
|
|
||||||
How far does the analogy go?
|
|
||||||
|
|
||||||
swarm of bees | a decentralised network of peers
|
|
||||||
-------|------------
|
|
||||||
living in a hive | form a distributed preimage archive
|
|
||||||
where they | where they
|
|
||||||
gather pollen | gather data chunks which they
|
|
||||||
to produce honey | transform into a longer data stream (document)
|
|
||||||
they consume and store | they serve and store
|
|
||||||
buzzing bzz | using bzz as their communications protocol
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
---
|
|
||||||
title: Swarm - distributed preimage archive
|
|
||||||
---
|
|
||||||
# Resources
|
|
||||||
|
|
||||||
## Swarm, the name
|
|
||||||
- https://www.facebook.com/swarmcorp, http://swarm.fund/
|
|
||||||
- https://bitcointalk.org/index.php?topic=650143.0
|
|
||||||
- https://bitcoinmagazine.com/17956/swarm-1-rick-falkvinges-swarmops-project/
|
|
||||||
- http://www.amazon.co.uk/Swarmwise-Tactical-Manual-Changing-World/dp/1463533152/
|
|
||||||
|
|
||||||
## Docs & specs
|
|
||||||
- [Swarm TODO](Swarm---TODO)
|
|
||||||
- Dani & Viktor on public wiki: https://github.com/ethereum/wiki/wiki/Distributed-Preimage-Archive
|
|
||||||
- Dani on swarm hash: https://github.com/ethereum/wiki/wiki/Swarm-Hash
|
|
||||||
- Dani on incentive system: https://github.com/ethersphere/swarm/blob/master/doc/incentives.md
|
|
||||||
- [The swarm smart contract](Swarm-Contract)
|
|
||||||
- gav on url-hint https://github.com/ethereum/wiki/wiki/URL-Hint-Protocol
|
|
||||||
- Gav on public wiki: https://github.com/ethereum/cpp-ethereum/wiki/Swarm
|
|
||||||
- network (DEVp2p)
|
|
||||||
- [Peer-to-Peer](Peer-to-Peer)
|
|
||||||
- on kademlia: https://github.com/ethereum/wiki/wiki/Cademlia-Peer-Selection
|
|
||||||
|
|
||||||
## Talks
|
|
||||||
- https://twitter.com/ethereumproject/status/538030376858693633
|
|
||||||
- Dr. Daniel Nagy: Ethereum ÐΞVcon-0: Keeping the Public Record Safe and Accessible - https://www.youtube.com/watch?v=QzYZQ03ON2o&list=PLJqWcTqh_zKEjpSej3ddtDOKPRGl_7MhS&index=7&spfreload=10
|
|
||||||
|
|
||||||
## Forum
|
|
||||||
- empty as of 01/2015: https://forum.ethereum.org/categories/swarm
|
|
||||||
-
|
|
||||||
|
|
||||||
## Mentions, discussions
|
|
||||||
- http://www.reddit.com/r/ethereum/comments/2d4uyw/swarm_and_whisper/
|
|
||||||
- http://www.reddit.com/r/ethereum/comments/2ityfz/ethereum_swarm/
|
|
||||||
- https://www.maidsafe.org/t/ethereums-swarm-p2p-storage-and-whisper-p2p-messaging/1528
|
|
||||||
- Vitalik's blogpost of 08/2014 - https://blog.ethereum.org/2014/08/16/secret-sharing-erasure-coding-guide-aspiring-dropbox-decentralizer/
|
|
||||||
- Vitalik: 'Swarm is out-of-scope': https://www.reddit.com/r/ethereum/comments/2phvml/constructive_criticism_of_ethereum_project_not/cmwtfqq
|
|
||||||
- Vitalik on eth components, swarm at 4:00 http://www.naation.com/2015/02/02/ethereum-explained-with-vitalik-buterin-inventor-and-leader-of-the-ethereum-project/5764/
|
|
||||||
- https://www.youtube.com/watch?v=zgkmQ-jQJHk&feature=youtu.be
|
|
||||||
|
|
||||||
## Media
|
|
||||||
- https://twitter.com/jeffehh/status/565927366271467521
|
|
||||||
- https://twitter.com/avsa/status/566255260713627648
|
|
||||||
- https://twitter.com/zeligf/status/566042020909973504
|
|
||||||
- https://www.reddit.com/r/ethereum/comments/2wryru/eli5_how_is_ethereum_supposed_to_be_a_dropbox
|
|
||||||
- https://forum.ethereum.org/discussion/comment/7593/#Comment_7593
|
|
||||||
|
|
||||||
## Code
|
|
||||||
- bzz PR: https://github.com/ethereum/go-ethereum/pull/255,
|
|
||||||
- repo https://github.com/ethersphere/go-ethereum/tree/bzz/
|
|
||||||
- ethereum p2p: https://github.com/ethereum/go-ethereum/p2p
|
|
||||||
- peer selection, peer pool: https://github.com/ethereum/go-ethereum/pull/253
|
|
||||||
- p2p cademlia branch (discontinued): https://github.com/ethersphere/go-ethereum/tree/kademlia
|
|
||||||
- Felix's node discovery code: https://github.com/ethereum/go-ethereum/tree/develop/p2p/discover
|
|
||||||
|
|
||||||
# Alternatives
|
|
||||||
|
|
||||||
- storj - http://storj.io/
|
|
||||||
- maidsafe - http://maidsafe.net/
|
|
||||||
- ipfs - http://ipfs.io/, https://www.youtube.com/watch?v=Fa4pckodM9g, http://static.benet.ai/t/ipfs.pdf, https://github.com/jbenet/go-ipfs, https://www.youtube.com/watch?v=8CMxDNuuAiQ, https://www.reddit.com/r/ethereum/comments/2wot2i/ipfs_alpha_demo/
|
|
||||||
- filecoin - http://filecoin.io/
|
|
||||||
- permacoin - https://www.cs.umd.edu/~elaine/docs/permacoin.pdf, https://bitcointalk.org/index.php?topic=640410.0, http://blog.dshr.org/2014/06/permacoin.html
|
|
||||||
- siacoin - http://www.siacoin.com/
|
|
||||||
- riak - http://basho.com/riak/
|
|
||||||
- BitTorrent http://www.bittorrent.com/ maelstrom http://blog.bittorrent.com/2014/12/10/project-maelstrom-the-internet-we-build-next/
|
|
||||||
- Tahoe-LAFS https://www.tahoe-lafs.org/trac/tahoe-lafs
|
|
||||||
- retroshare http://retroshare.sourceforge.net/
|
|
||||||
|
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
---
|
|
||||||
title: Swarm channels, namereg-resolution draft
|
|
||||||
---
|
|
||||||
# Channels and streams
|
|
||||||
|
|
||||||
a *swarm chain* is an ordered list of content that are linked as a forkless chain.
|
|
||||||
.
|
|
||||||
This is simply modeled as linked manifests.
|
|
||||||
|
|
||||||
a *channel* is a sequence of manifests (_S_) and a relative path _P_ with a starting manifest _M_ and a streamsize _n_ (can be infinite). A channel is well-formed or regular if in every manifest in the stream _P_ resolves to a consistent mime type _T_ . For instance , if _T_ is `application/bzz-manifest+json`, we say the channel is a _manifest channel_, if the mime-type is `mpeg`, its a video channel.
|
|
||||||
|
|
||||||
A *primary channel* is a channel that actually respect chronological order of creation.
|
|
||||||
|
|
||||||
A *live channel* is a primary channel that keeps updating (adding episodes to the end of the chain) can have a (semi)-persistent mime-type for path _P_
|
|
||||||
|
|
||||||
A *blockstream channel* is a primary channel provable linked in time via hashes.
|
|
||||||
|
|
||||||
A *signed channel* is a primary channel provably linked by signatures (sequence position index signed by the publisher)
|
|
||||||
|
|
||||||
*Trackers* are a manifest channel which tracks updates to a primary channel and provides forward linking .
|
|
||||||
|
|
||||||
## Example channels:
|
|
||||||
|
|
||||||
- name histories, e.g updates of a domain, temporal snapshots of content
|
|
||||||
- blockchain: blockchain is a special case of blockstream
|
|
||||||
- git graph, versioning
|
|
||||||
- modeling a source of information: provable communication with hash chain, not allowed to fork, numbered.
|
|
||||||
|
|
||||||
#### content trackers
|
|
||||||
|
|
||||||
reverse index of a stream
|
|
||||||
- contains `next` links to following state
|
|
||||||
- published after next state
|
|
||||||
- publish provable quality metrics:
|
|
||||||
- age: starting date of tracker vs date of orig content
|
|
||||||
- neg exp forgetting(track date vs primary date of next episode) ~ alertness, puncuality (tracker
|
|
||||||
- git version control
|
|
||||||
|
|
||||||
every named host defines a timeline,
|
|
||||||
- create a manifest stream tracking a site
|
|
||||||
|
|
||||||
## Ways to link manifests
|
|
||||||
|
|
||||||
#### examples
|
|
||||||
|
|
||||||
``` json
|
|
||||||
{ "entries":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"host": "fefe.eth",
|
|
||||||
"number": 9067,
|
|
||||||
"previous": "ffca34987",
|
|
||||||
"next": "aefbc4569ab",
|
|
||||||
"this": "90daefaaabbc",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"auth": "3628aeefbc7689523aebc2489",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# Name resolution
|
|
||||||
|
|
||||||
The host part in a bzz webaddress should be resolved with our version of DNS, ie. using both `NameReg` (name registration contract on ethereum) and a simple mutable storage in swarm.
|
|
||||||
|
|
||||||
## signed version store
|
|
||||||
The point of channels (Swarm---Channels
|
|
||||||
) is to have a total order over a set of manifests.
|
|
||||||
|
|
||||||
The typical usecase is that it should be enough to know the name of a site or document to always see the latest version of a software or get the current episode of your favourite series or the consensus state of a blockchain. It should also be possible to deterministically derive the key to future content...
|
|
||||||
|
|
||||||
One possibility is to modify the NameReg entry in the blockchain to point to a swarm hash. Recording each change on the blockchain results in an implicit live channel linking. This scheme is simple inasmuch as it puts authentication completely on the chain. However, it is expensive and not viable given the number of publishers and typical rate of update.
|
|
||||||
|
|
||||||
Alternatively, swarm provides the protocol for associating a channel and a position with a swarm hash. The versioning can be authenticated since a message containing host name, sequence position index and swarm hash is signed by the public key registered in ethereum NameReg for the host.
|
|
||||||
|
|
||||||
Publishers, fans or paid bookkeepers track updates of a channel and wrap accumulated messages into a tracker manifest.
|
|
||||||
Most probably publishers would broadcast updates of a channel manifest in the first place.
|
|
||||||
|
|
||||||
This special key-value store can be implemented as a mutable store: the value with a higher index will simply override the previous one.
|
|
||||||
|
|
||||||
There can be various standards to derive lookup key deterministically
|
|
||||||
the simplest one is `HASH(host:version)` for a specific version and `HASH(host)` for the latest version.
|
|
||||||
The content has the following structure:
|
|
||||||
|
|
||||||
```
|
|
||||||
sign[<host>, <version>, <timestamp>, <hash>]
|
|
||||||
```
|
|
||||||
|
|
||||||
Retrieve request for a signed version is the same as a request for a hash.
|
|
||||||
|
|
||||||
[RetrieveMsg, HASH(host:version), id, timeout, MUTABLE]
|
|
||||||
[RetrieveMsg, HASH(host:0), id, timeout, MUTABLE]
|
|
||||||
|
|
||||||
Store request for a signed version is the same as for a hash:
|
|
||||||
|
|
||||||
[StoreMsg, key, id, MUTABLE, Sign[host, version, time.Unix(), hash]]
|
|
||||||
|
|
||||||
## Format
|
|
||||||
It is up to debate how we distinguish names to be resolved.
|
|
||||||
|
|
||||||
An early idea was to use a top level domain, such as `.eth` (<source> == `<host>.eth`)
|
|
||||||
this might limit the possibilities
|
|
||||||
|
|
||||||
Another idea was to have it as or part of the protocol: `eth://my-website.home` or `eth+bzz://my-website.home`. This are semantically incorrect, however.
|
|
||||||
|
|
||||||
Third, put an _eth_ inside the host somehow.
|
|
||||||
|
|
||||||
Ad-hoc constructs like `bzz://eth:my-website.home` will be rejected by host pattern matchers.
|
|
||||||
|
|
||||||
Abusing subdomains `bzz://eth.my-website.home` would cause ambiguity and potential collision.
|
|
||||||
Abusing auth `user:pass@my-website.home` would disable basic auth.
|
|
||||||
|
|
||||||
A suggestion that most aligns with the *signed versioning* and very simple is that we look up everything that is not a 32 byte hash format for a public key. The version of the site is looked up using the port part of the host. A specific version is given after the `:`.
|
|
||||||
|
|
||||||
The generic pattern then:
|
|
||||||
|
|
||||||
```
|
|
||||||
(<version_chain>.)<host>(:<number>)(/<path>)
|
|
||||||
```
|
|
||||||
|
|
||||||
### example 0
|
|
||||||
```
|
|
||||||
bzz://breaking.bad.tv/s4/e2/video
|
|
||||||
```
|
|
||||||
- _breaking.bad.tv_ is looked up in NameReg to yield public key _P_
|
|
||||||
- _breaking.bad.tv_ is looked up in the immutable store to yield a message `[_breaking.bad.tv_,0,3,aebf45fbf6ae6aaaafedcbcb467]`
|
|
||||||
- `aebf45fbf6ae6aaaafedcbcb467` is looked up in swarm to yield the manifest
|
|
||||||
- manifest entry for path `/s4/e2/video` results in the actual document's root key
|
|
||||||
|
|
||||||
### example 1
|
|
||||||
```
|
|
||||||
bzz://breaking.bad.tv/video
|
|
||||||
```
|
|
||||||
resolves the following way:
|
|
||||||
- _breaking.bad.tv_ is looked up in NameReg to yield public key _P_
|
|
||||||
- _breaking.bad.tv_ is looked up in the immutable store to yield - by `H(cookie)` - a message `[_breaking.bad.tv_,s5:e12,3,aebf45fbf6ae6aaaafedcbcb467]` signed by `P`
|
|
||||||
- `aebf45fbf6ae6aaaafedcbcb467` is looked up in swarm to yield the manifest
|
|
||||||
- manifest entry for path `video` results in the actual document's root key
|
|
||||||
|
|
||||||
### example 2
|
|
||||||
```
|
|
||||||
bzz://current.breaking.bad.tv:s4:e10/video
|
|
||||||
```
|
|
||||||
- _breaking.bad.tv_ is looked up in NameReg to yield public key _P_
|
|
||||||
- current.breaking.bad.tv:s4:e10 is looked up in the immutable store to yield a message `[current.breaking.bad.tv,s4:e10,3,45fbf6ae6aaaafedcbcb467ccc]`
|
|
||||||
- `45fbf6ae6aaaafedcbcb467ccc` is looked up in swarm to yield the manifest
|
|
||||||
- manifest entry for path `video` results in the actual document's root key
|
|
||||||
|
|
||||||
### example 3
|
|
||||||
```
|
|
||||||
bzz://breaking.bad.tv/playlist
|
|
||||||
```
|
|
||||||
- same as ex 2...
|
|
||||||
- manifest entry for path `playlist` results in a playlist manifest
|
|
||||||
|
|
||||||
|
|
||||||
### example 4
|
|
||||||
```
|
|
||||||
bzz://stable.ethereum.org:8.1/download/go/mac-os
|
|
||||||
```
|
|
||||||
- _stable.ethereum.org_ is looked up in NameReg to yield public key _P_
|
|
||||||
- stable.ethereum.org:s4:e10 is looked up in the immutable store to yield a message `[stable.ethereum.org,s4:e10,3,45fbf6ae6aaaafedcbcb467ccc]`
|
|
||||||
- `45fbf6ae6aaaafedcbcb467ccc` is looked up in swarm to yield the manifest
|
|
||||||
- manifest entry for path `video` results in the actual document's root key
|
|
||||||
|
|
||||||
Generalised content streaming, subscriptions.
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
title: Swarm contract
|
|
||||||
---
|
|
||||||
This one contract regulates the incentive structure of Swarm.
|
|
||||||
|
|
||||||
The corresponding solidity code can be browsed [here](https://github.com/ethersphere/go-ethereum/blob/bzz/bzz/bzzcontract/swarm.sol).
|
|
||||||
|
|
||||||
# Methods
|
|
||||||
|
|
||||||
## Sign up as a node
|
|
||||||
|
|
||||||
Pay a deposit in Ether and register public key. Comes with an accessor for checking that a node is signed up.
|
|
||||||
|
|
||||||
## Demand penalty for loss of chunk
|
|
||||||
|
|
||||||
Present a signed receipt by a signed up node and a deposit covering the upload of a chunk. After a given deadline, the signer node's deposit is taken and the presenting node's deposit refunded, unless the chunk is presented. Comes with an accessor for checking that a given chunk has been reported lost, so that holders of receipts by other swarm nodes can punish them as well for losing the chunk, which, in turn, incentivizes whoever holds the chunk to present it.
|
|
||||||
|
|
||||||
## Present chunk to avoid penalty
|
|
||||||
|
|
||||||
No penalty is paid for lost chunks, if chunk is presented within the deadline. The cost of uploading the chunk is compensated exactly from the demand's deposit, with the remainder refunded. Comes with an accessor for checking that a given node is liable for penalty, so the node is notified to present the chunk in a timely fashion.
|
|
||||||
|
|
||||||
# Price considerations
|
|
||||||
|
|
||||||
For the price of accepting a chunk for storing, see [Incentives](https://github.com/ethersphere/swarm/blob/master/doc/incentives.md)
|
|
||||||
|
|
||||||
This price should be proportional to the sign-up deposit of the swarm node.
|
|
||||||
|
|
||||||
The deposit for compensating the swarm node for uploading the chunk into the block chain should be substantially higher (e.g. a small integer multiple) of the corresponding upload measured with the gas price used to upload the demand to prevent DoS attacks.
|
|
||||||
|
|
||||||
# Termination
|
|
||||||
|
|
||||||
Users of Swarm should be able to count on the loss of deposit as a disincentive, so it should not be refunded before the term of Swarm membership expires. If penalites were paid out as compensation to holders of receipts of lost chunks, it would provide an avenue of early exit for a Swarm member by "losing" chunks deposited by colluding users. Since users of Swarm are interested in their information being reliably stored, their primary incentive for keeping the receipts is to keep the Swarm motivated, not the potential compensation.
|
|
||||||
|
|
||||||
# Receipt circulation
|
|
||||||
|
|
||||||
End-users of Swarm keeping important information in it are obviously interested in keeping as many receipts of it as possible available for "litigation". The storage space required for storing a receipt is a sizable fraction of that used for storing the information itself, so end users can reduce their storage requirement further by storing the receipts in Swarm as well. Doing this recursively would result in end users only having to store a single receipt, yet being
|
|
||||||
able to penalize quite a few Swarm nodes, in case only a small part of their stored information
|
|
||||||
is lost.
|
|
||||||
|
|
||||||
Swarm nodes that use the rest of Swarm as a backup may want to propagate the receipts in the opposite direction of storage requests, so that the cost of storing receipts is eventually paid by the end user either in the form of allocated storage space or as a direct payment to Swarm.
|
|
|
@ -1,141 +0,0 @@
|
||||||
---
|
|
||||||
title: Tracing / Introduction
|
|
||||||
---
|
|
||||||
There are two different types of transactions in Ethereum: plain value transfers and contract executions. A plain value transfer just moves Ether from one account to another and as such is uninteresting from this guide's perspective. If however the recipient of a transaction is a contract account with associated 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 arbitrarilly 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 intertwined ecosystem of contracts, where a single transaction can interact with tens or hunderds 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's no way to see what data was modified, nor what external contracts where invoked. In order to introspect a transaction, we need to trace its execution.
|
|
||||||
|
|
||||||
## 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, it needs to have available all historical state accessed by the transaction:
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
Depending on your node's mode of synchronization and pruning, different configurations result in different capabilities:
|
|
||||||
|
|
||||||
* An **archive** node retaining **all historical data** can trace arbitrary transactions at any point in time. Tracing a single transaction also entails reexecuting all preceding transactions in the same block.
|
|
||||||
* A **fast synced** node retaining **all historical data** after initial sync can only trace transactions from blocks following the initial sync point. Tracing a single transaction also entails reexecuting all preceding transactions in the same block.
|
|
||||||
* A **fast synced** node retaining only **periodic state data** after initial sync can only trace transactions from blocks following the initial sync point. Tracing a single transaction entails reexecuting all preceding transactions **both** in the same block, as well as 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. In practice, data availability is **not** a feasible assumption.
|
|
||||||
|
|
||||||
*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 `go-ethereum` 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*.
|
|
||||||
|
|
||||||
An example log entry for a single opcode looks like:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"pc": 48,
|
|
||||||
"op": "DIV",
|
|
||||||
"gasCost": 5,
|
|
||||||
"gas": 64532,
|
|
||||||
"depth": 1,
|
|
||||||
"error": null,
|
|
||||||
"stack": [
|
|
||||||
"00000000000000000000000000000000000000000000000000000000ffffffff",
|
|
||||||
"0000000100000000000000000000000000000000000000000000000000000000",
|
|
||||||
"2df07fbaabbe40e3244445af30759352e348ec8bebd4dd75467a9f29ec55d98d"
|
|
||||||
],
|
|
||||||
"memory": [
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000060"
|
|
||||||
],
|
|
||||||
"storage": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The entire output of an 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* that take the above form:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"gas": 25523,
|
|
||||||
"failed": false,
|
|
||||||
"returnValue": "",
|
|
||||||
"structLogs": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generating basic traces
|
|
||||||
|
|
||||||
To generate a raw EVM opcode trace, `go-ethereum` provides a few [RPC API endpoints](https://github.com/ethereum/go-ethereum/wiki/Management-APIs), out of which the most commonly used is [`debug_traceTransaction`](https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug_tracetransaction).
|
|
||||||
|
|
||||||
In its simplest form, `traceTransaction` accepts a transaction hash as its sole argument, 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 of course be invoked from outside the node too via HTTP RPC. In this case, please make sure the HTTP endpoint is enabled via `--rpc` and the `debug` API namespace exposed via `--rpcapi=debug`.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f"]}' localhost:8545
|
|
||||||
```
|
|
||||||
|
|
||||||
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).
|
|
||||||
|
|
||||||
### Tuning basic traces
|
|
||||||
|
|
||||||
By default the raw opcode tracer emits all relevant events that occur within the EVM while processing a transaction, such as *EVM stack*, *EVM memory* and *updated storage slots*. Certain use cases however may not need some of these data fields reported. To cater for those use cases, these massive fields may be omitted using a second *options* parameter for the tracer:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"disableStack": true,
|
|
||||||
"disableMemory": true,
|
|
||||||
"disableStorage": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Running the previous tracer invocation from the Geth console with the data fields disabled:
|
|
||||||
|
|
||||||
```js
|
|
||||||
debug.traceTransaction("0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f", {disableStack: true, disableMemory: true, disableStorage: true})
|
|
||||||
```
|
|
||||||
|
|
||||||
Analogously running the filtered tracer from outside the node too via HTTP RPC:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f", {"disableStack": true, "disableMemory": true, "disableStorage": true}]}' localhost:8545
|
|
||||||
```
|
|
||||||
|
|
||||||
Running the above operation on the Rinkeby network will result in this significantly shorter [trace dump](https://gist.github.com/karalabe/d74a7cb33a70f2af75e7824fc772c5b4).
|
|
||||||
|
|
||||||
### Limits of basic traces
|
|
||||||
|
|
||||||
Although the raw opcode traces we've generated above have their use, this basic way of tracing is problematic in the real world. 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 all of the previously mentioned issues, `go-ethereum` supports running custom JavaScript tracers *within* the Ethereum node, which have full access to the EVM stack, memory and contract storage. This permits developers to only gather the data they need, and do any processing **at** the data. Please see the next section for our *custom in-node tracers*.
|
|
||||||
|
|
||||||
### Pruning
|
|
||||||
|
|
||||||
Geth by default does in-memory pruning of state, discarding state entries that it deems is no longer necessary to maintain. This is configured via the `--gcmode` option. Often, people run into the error that state is not available.
|
|
||||||
|
|
||||||
Say you want to do a trace on block `B`. Now there are a couple of cases:
|
|
||||||
|
|
||||||
1. You have done a fast-sync, pivot block `P` where `P <= B`.
|
|
||||||
2. You have done a fast-sync, pivot block `P` where `P > B`.
|
|
||||||
3. You have done a full-sync, with pruning
|
|
||||||
4. You have done a full-sync, without pruning (`--gcmode=archive`)
|
|
||||||
|
|
||||||
Here's what happens in each respective case:
|
|
||||||
|
|
||||||
1. Geth will regenerate the desired state by replaying blocks from the closest point in time before `B` where it has full state. This defaults to [`128`](https://github.com/ethereum/go-ethereum/blob/master/eth/api_tracer.go#L52) blocks max, but you can specify more in the actual call `... "reexec":1000 .. }` to the tracer.
|
|
||||||
2. Sorry, can't be done without replaying from genesis.
|
|
||||||
3. Same as 1)
|
|
||||||
4. Does not need to replay anything, can immediately load up the state and serve the request.
|
|
||||||
|
|
||||||
There is one other option available to you, which may or may not suit your needs. That is to use [Evmlab]( https://github.com/holiman/evmlab).
|
|
||||||
```
|
|
||||||
docker pull holiman/evmlab && docker run -it holiman/evmlab
|
|
||||||
```
|
|
||||||
There you can use the reproducer. The reproducer will incrementally fetch data from infura until it has all the information required to create the trace locally on an evm which is bundled with the image. It will create a custom genesis containing the state that the transaction touches (balances, code, nonce etc). It should be mentioned that the evmlab reproducer is strictly guaranteed to be totally exact with regards to gascosts incurred by the outer transaction, as evmlab does not fully calculate the gascosts for nonzero data etc, but is usually sufficient to analyze contracts and events.
|
|
|
@ -1,270 +0,0 @@
|
||||||
---
|
|
||||||
title: URL Scheme
|
|
||||||
---
|
|
||||||
# URLs in DAPP browsers
|
|
||||||
|
|
||||||
URLs should contain all allowable urls in browsers and _all_ `http(s)` urls that resolve in a usual browser must resolve the same way.
|
|
||||||
|
|
||||||
All urls not conforming to the existing urls scheme must still resemble the current urls scheme.
|
|
||||||
|
|
||||||
```
|
|
||||||
<protocol>://<source>/<path>
|
|
||||||
```
|
|
||||||
|
|
||||||
Irrespective of the main protocol, `<source>` should be resolved with our version of DNS (`NameReg` (ename registration contract on ethereum) and/or via swarm signed version stream.
|
|
||||||
|
|
||||||
In the special case of the bzz protocol, `<source>` must resolve to a Swarm hash of the content (in other words, the root key of the content). This content is assumed to be of mime type `application/bzz-sitemap+json` the only mime-type directly handled by Swarm.
|
|
||||||
|
|
||||||
# Swarm manifests
|
|
||||||
|
|
||||||
A Swarm manifest is a json formatted description of url routing.
|
|
||||||
The swarm manifest allows swarm documents to act as file systems or webservers.
|
|
||||||
Their mime type is `application/bzz-sitemap+json`
|
|
||||||
Manifest has the following attributes:
|
|
||||||
|
|
||||||
- `entries`: an array of route configurations
|
|
||||||
- `host`: eth host name registered (or to register) with NameReg
|
|
||||||
- `number`: position index (increasing integers) of manifest within channel,
|
|
||||||
- `auth`: devp2p cryptohandshake public key(s), signed number
|
|
||||||
- `first`: root key of initial state of the stream
|
|
||||||
- `previous`: previous state of stream
|
|
||||||
|
|
||||||
A route descriptor manifest entry json object has the following attributes:
|
|
||||||
|
|
||||||
- `path`: a path relative to the url that resolved to the manifest (_optional, with empty default_)
|
|
||||||
- `hash`: key of the content to be looked up by swarm (_optional_)
|
|
||||||
- `link`: relative path or external link (_optional_)
|
|
||||||
- `contentType`: mime type of the content (_optional, `application/bzz-server` by default_)
|
|
||||||
- `status`: optional http status code to pass back to the server (_optional, 200 by default_)
|
|
||||||
- `cache`: cache entry, etag? and other header options (_optional_)
|
|
||||||
- `www`: alternative old web address that the route replicates: e.g., `http://eth:bzz@google.com` (_optional_)
|
|
||||||
|
|
||||||
If `path` is an empty string or is missing, the path matches the _document-root_ of the DAPP.
|
|
||||||
If `contentType` is empty or missing, manifest if assumed by default.
|
|
||||||
|
|
||||||
(NOTE: Unclear. When no path matches and there is no fallback path e.g. a root `/` path with hash specified, it should return a simple 404 status code)
|
|
||||||
|
|
||||||
# Url resolution
|
|
||||||
|
|
||||||
Given
|
|
||||||
|
|
||||||
```
|
|
||||||
bzz://<source>/<path>
|
|
||||||
```
|
|
||||||
|
|
||||||
in the browser, the following steps need to happen:
|
|
||||||
|
|
||||||
- the browser sees that its bzz protocol `<source>/<path>` is passed to the *bzz protocol handler*,
|
|
||||||
- the handler checks if `<source>` is a hash. If not it resolves to a hash via NameReg and signed version table, see below
|
|
||||||
- the bzz protocol handler first retrieves the content for the hash (with integrity check) which it interprets as a manifest file (`application/bzz-sitemap+json`),
|
|
||||||
- this manifest file is then parsed, read and the json array element with the longest prefix `p` of `<path>` is looked up. I.e., `p` is the longest prefix such that `<path> == p'/p''`. (If the longest prefix is 0 length, the row with `<path> == ""` (or left out) is chosen.)
|
|
||||||
- as a special case, trailing forward slashes are ignored so all variants will match the directory,
|
|
||||||
- the protocol then looks up content for `p'` and serves it to the browser together with the status code and content type.
|
|
||||||
- if content is of type manifest, bzz retrieves it and repeats the steps using `p''` to match the manifest's `<path>` values against,
|
|
||||||
- the url relative path is set to `p''`
|
|
||||||
- if the url looked up is an old-world http site, then a standard http client call is sufficient.
|
|
||||||
|
|
||||||
### Example 1
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
entries: [
|
|
||||||
{
|
|
||||||
"path": "cv.pdf",
|
|
||||||
"contentType": "document/pdf",
|
|
||||||
"hash": "sdfhsd76ftsd86ft76sdgf78h7tg",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
where the hash is the hash of the actual file `cv.pdf`.
|
|
||||||
|
|
||||||
If this manifest hashes to `dafghjfgsdgfjfgsdjfgsd`, then `bzz://dafghjfgsdgfjfgsdjfgsd/cv.pdf` will serve `cv.pdf`
|
|
||||||
|
|
||||||
Now you can register the manifest hash with NameReg to resolve `my-website` the file as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
http://my-website/cv.pdf
|
|
||||||
```
|
|
||||||
|
|
||||||
serves `cv.pdf`
|
|
||||||
|
|
||||||
### Example 2
|
|
||||||
Imagine you have a DAPP called _chat_ and host it under
|
|
||||||
your local directory `<dir>` looks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
index.html
|
|
||||||
img/logo.gif
|
|
||||||
img/avatars/fefe.jpg
|
|
||||||
img/avatars/index.html
|
|
||||||
```
|
|
||||||
|
|
||||||
the webserver has the following routing rules:
|
|
||||||
|
|
||||||
```
|
|
||||||
-> <dir>/index.html
|
|
||||||
<unkwown> -> <dir>/index.html # where <unknown> != index.html
|
|
||||||
img/logo.gif -> <dir>/img/logo.gif
|
|
||||||
img/avatars -> <dir>img/avatars/index.html
|
|
||||||
img/avatars/fefe.jpg -> <dir>/img/avatars/fefe.jpg
|
|
||||||
img/avatars/<unknown>.jpg <dir>/img/avatars/index.html # where <unknown> != fefe.jpg
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can alternatively host your app in Swarm by creating the following manifest:
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
"entries": [
|
|
||||||
{ "hash": HASH(<dir>/index.html) },
|
|
||||||
{ "path": "index.html", "hash": HASH(<dir>/index.html) },
|
|
||||||
{ "path": "img/logo.gif", "hash": HASH(<dir>/img/logo.gif) },
|
|
||||||
{ "path": "img/avatars/", "hash": HASH(<dir>/img/avatars/index.html) },
|
|
||||||
{ "path": "img/avatars/fefe.jpg", "hash": HASH(img/avatars/fefe.jpg) }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# Swarm webservers
|
|
||||||
|
|
||||||
Swarm webservers are simply bzz site manifest files routing relative paths to static assets.
|
|
||||||
Manifest route entries specify metadata: http header values, etag, redirects, links, etc.
|
|
||||||
|
|
||||||
In a typical scenario, the developer has a website within a working copy directory on their dev environment and they want to create a decentralised version of their site.
|
|
||||||
|
|
||||||
They then register the host domain with ethereum NameReg or swarm signed version stream, upload all desired static assets to swarm, and produce a site manifest.
|
|
||||||
|
|
||||||
In order to facilitate the creation of the manifest file for existing web projects, a native API and a command line utility are provided to automatically generate manifest files from a directory.
|
|
||||||
|
|
||||||
## ArcHive API
|
|
||||||
|
|
||||||
A native API and a command line utility are provided to automatically swarmify document collections.
|
|
||||||
constructor parameters:
|
|
||||||
|
|
||||||
- `template`: manifest template: the entries found in the directory scan are merged into this template to yield the resulting site-map. Note that this template can be considered a config file to the archiver.
|
|
||||||
|
|
||||||
The archiver can be called multiple times scanning multiple directories.
|
|
||||||
|
|
||||||
runtime parameters:
|
|
||||||
- `path`: path to directory relative routes in the template matched against directory paths under `path` (_optional_, '.' by default).
|
|
||||||
- `not-found`: errorchange to be used when asset is not found: for 404, (_optional_, `index.html`)
|
|
||||||
- `register-names` use eth NameReg to register public key and this version is pushed to swarm mutable store (_optional_, _false_)
|
|
||||||
- `without-scan` only consider paths given in template (_optional_, by default _false_: in template, scan directory and add/merge all readable content to manifest)
|
|
||||||
- `without-upload`: files are not uploaded, only hashes are calculated and manifest is created (_optional_, _false_, upload every asset to swarm)
|
|
||||||
|
|
||||||
If both `without-scan` and `without-upload` are omitted then `path` is used to associate files, extend the manifest entries, and upload content.
|
|
||||||
|
|
||||||
if `register-names` is set all named nodes.
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"path": "chat",
|
|
||||||
"hash": "sdfhsd76ftsd86ft76sdgf78h7tg",
|
|
||||||
"status": 200,
|
|
||||||
"contentType": "document/pdf"
|
|
||||||
},
|
|
||||||
...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Without swarm, the zip fallback
|
|
||||||
|
|
||||||
namereg resolution:
|
|
||||||
|
|
||||||
`contentOf('eth/wallet') -> 324234kj23h4kj2h3kj423kj4h23`
|
|
||||||
|
|
||||||
This name reg has also a `urlOf` where it can find the file (e.g. from a raw pastebin)
|
|
||||||
|
|
||||||
It then downloads the file, extracts it and resolves all relative/absolute paths, based on the manifest it finds in it.
|
|
||||||
|
|
||||||
For the developer, the upload mechanism in mix will be the same, as he chooses a folder and can provide a `serverconfig.json` (or manfiest)
|
|
||||||
|
|
||||||
The only difference is the lookup and where it gets the files from.
|
|
||||||
|
|
||||||
```
|
|
||||||
swarm -> content hashes
|
|
||||||
before swarm -> zip file content
|
|
||||||
```
|
|
||||||
|
|
||||||
And both are resolved through the same manifest scheme
|
|
||||||
|
|
||||||
## Server config examples:
|
|
||||||
|
|
||||||
URL: bzz://dsf32f3cdsfsd/somefolder/other
|
|
||||||
Same as: eth://myname.reggae/somefolder/other
|
|
||||||
|
|
||||||
We should also map folder with and without "/" so that the path lookup for path: "/something/myfolder" is the same as "/something/myfolder/"
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
previous: 'jgjgj67576576576567ytjy',
|
|
||||||
first: 'ds564rh5656hhfghfg',
|
|
||||||
entries:[{
|
|
||||||
// Custom error page
|
|
||||||
path: '/i18n/',
|
|
||||||
file: '/errorpages/404.html',
|
|
||||||
// parses "file" when processing the folder and add: hash: '7685trgdrreewr34f34', contentType: 'text/html'
|
|
||||||
status: 404
|
|
||||||
|
|
||||||
},{
|
|
||||||
// custom fallback file for this folder: "/images/sdffsdfds/"
|
|
||||||
path: '/images/sdffsdfds/',
|
|
||||||
file: '/index.html',
|
|
||||||
// parses "file" when processing the folder and add: hash: '345678678678678678tryrty', contentType: 'text/html'
|
|
||||||
|
|
||||||
},{
|
|
||||||
// custom fallback file with custom header.
|
|
||||||
path: '/',
|
|
||||||
file: '/index.html',
|
|
||||||
// parses "file" when processing the folder and add: hash: '434534534f34k234234hrkj34hkjrh34', contentType: 'text/html'
|
|
||||||
status: 500
|
|
||||||
|
|
||||||
},{
|
|
||||||
// redirect (changing url after?)
|
|
||||||
path: '/somefolder/',
|
|
||||||
redirect: 'http://google.com'
|
|
||||||
|
|
||||||
},{
|
|
||||||
// linking?
|
|
||||||
path: '/somefolder/other/',
|
|
||||||
link: 'bzz://43greg45gerg5t45gerge/chat/' // hash to another manifest
|
|
||||||
|
|
||||||
},{
|
|
||||||
// downloading a file by pointing to a folder
|
|
||||||
path: '/somefolder/other/',
|
|
||||||
file: '/mybook.pdf',
|
|
||||||
// parses "file" when processing the folder and add: hash: '645325ytrhfgdge4tgre43f34', BUT no contentType, as its already present
|
|
||||||
contentType: 'application/octet-stream' // trigger a download in the browser for this link)
|
|
||||||
|
|
||||||
},{
|
|
||||||
// downloading
|
|
||||||
path: '/test.html',
|
|
||||||
file: '/test.html',
|
|
||||||
// parses "file" when processing the folder and add: hash: '645325ytrhfgdge4tgre43f34', BUT no contentType, as its already present
|
|
||||||
contentType: 'application/octet-stream' // trigger a download in the browser for this link)
|
|
||||||
|
|
||||||
// automatic generated files
|
|
||||||
},{
|
|
||||||
path: '/i18n/app.en.json',
|
|
||||||
hash: '456yrtgfds43534t45',
|
|
||||||
contentType: 'text/json',
|
|
||||||
},{
|
|
||||||
path: '/somefolder/other/image.png',
|
|
||||||
hash: '434534534f34khrkj34hkjrh34',
|
|
||||||
contentType: 'image/png',
|
|
||||||
},{
|
|
||||||
path: '/somefolder/other/343242.png',
|
|
||||||
hash: '434534534f34k234234hrkj34hkjrh34',
|
|
||||||
contentType: 'image/png',
|
|
||||||
},{
|
|
||||||
path: '/somefold/frau.png',
|
|
||||||
hash: 'sdfsdfsdfsdfsdfsdfsd',
|
|
||||||
contentType: 'image/png',
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,172 +0,0 @@
|
||||||
---
|
|
||||||
title: Whisper overview
|
|
||||||
---
|
|
||||||
## Whisper Overview
|
|
||||||
|
|
||||||
Whisper is a pure identity-based messaging system. Whisper provides a simple low-level API without being based upon or influenced by the low-level hardware attributes and characteristics. Peer-to-peer communication between the nodes of Whisper network uses the underlying [ÐΞVp2p Wire Protocol](https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol). Whisper was not designed to provide a connection-oriented system, nor for simply delivering data between a pair of particular network endpoints. However, this might be necessary in some very specific cases (e.g. delivering the expired messages in case they were missed), and Whisper protocol will accommodate for that. Whisper is designed for easy and efficient broadcasting, and also for low-level asynchronous communications. It is designed to be a building block in next generation of unstoppable ÐApps. It was designed to provide resilience and privacy at considerable expense. At its most secure mode of operation, Whisper can theoretically deliver 100% darkness. Whisper should also allow the users to configure the level of privacy (how much information it leaks concerning the ÐApp content and ultimately, user activities) as a trade-off for performance.
|
|
||||||
|
|
||||||
Basically, all Whisper messages are supposed to be sent to every Whisper node. In order to prevent a DDoS attack, proof-of-work (PoW) algorithm is used. Messages will be processed (and forwarded further) only if their PoW exceeds a certain threshold, otherwise they will be dropped.
|
|
||||||
|
|
||||||
### Encryption in version 5
|
|
||||||
|
|
||||||
All Whisper messages are encrypted and then sent via underlying ÐΞVp2p Protocol, which in turn uses its own encryption, on top of Whisper encryption. Every Whisper message must be encrypted either symmetrically or asymmetrically. Messages could be decrypted by anyone who possesses the corresponding key.
|
|
||||||
|
|
||||||
In previous versions unencrypted messages were allowed, but since it was necessary to exchange the topic (more on that below), the nodes might as well use the same communication channel to exchange encryption key.
|
|
||||||
|
|
||||||
Every node may possess multiple symmetric and asymmetric keys. Upon Envelope receipt, the node should try to decrypt it with each of the keys, depending on Envelope's encryption mode -- symmetric or asymmetric. In case of success, decrypted message is passed to the corresponding Ðapp. In any case, every Envelope should be forwarded to each of the node's peers.
|
|
||||||
|
|
||||||
Asymmetric encryption uses the standard Elliptic Curve Integrated Encryption Scheme with SECP-256k1 public key. Symmetric encryption uses AES GCM algorithm with random 96-bit nonce. If the same nonce will be used twice, then all the previous messages encrypted with the same key will be compromised. Therefore no more than 2^48 messages should be encrypted with the same symmetric key (for detailed explanation please see the Birthday Paradox). However, since Whisper uses proof-of-work, this number could possibly be reached only under very special circumstances (e.g. private network with extremely high performance and reduced PoW). Still, usage of one-time session keys is strongly encouraged for all Ðapps.
|
|
||||||
|
|
||||||
Although we assume these standard encryption algorithms to be reasonably secure, users are encouraged to use their own custom encryption on top of the default Whisper encryption.
|
|
||||||
|
|
||||||
#### Envelopes
|
|
||||||
|
|
||||||
Envelopes are the packets sent and received by Whisper nodes. Envelopes contain the encrypted payload and some metadata in plain format, because these data is essential for decryption. Envelopes are transmitted as RLP-encoded structures of the following format:
|
|
||||||
|
|
||||||
[ Version, Expiry, TTL, Topic, AESNonce, Data, EnvNonce ]
|
|
||||||
|
|
||||||
Version: up to 4 bytes (currently one byte containing zero). Version indicates encryption method. If Version is higher than current, envelope could not be decrypted, and therefore only forwarded to the peers.
|
|
||||||
|
|
||||||
Expiry time: 4 bytes (UNIX time in seconds).
|
|
||||||
|
|
||||||
TTL: 4 bytes (time-to-live in seconds).
|
|
||||||
|
|
||||||
Topic: 4 bytes of arbitrary data.
|
|
||||||
|
|
||||||
AESNonce: 12 bytes of random data (only present in case of symmetric encryption).
|
|
||||||
|
|
||||||
Data: byte array of arbitrary size (contains encrypted message).
|
|
||||||
|
|
||||||
EnvNonce: 8 bytes of arbitrary data (used for PoW calculation).
|
|
||||||
|
|
||||||
Whisper nodes know nothing about content of envelopes which they can not decrypt. The nodes pass envelopes around regardless of their ability to decrypt the message, or their interest in it at all. This is an important component in Whisper's dark communications strategy.
|
|
||||||
|
|
||||||
#### Messages
|
|
||||||
|
|
||||||
Message is the content of Envelope's payload in plain format (unencrypted).
|
|
||||||
|
|
||||||
Plaintext (unencrypted) message is formed as a concatenation of a single byte for flags, additional metadata (as stipulated by the flags) and the actual payload. The message has the following structure:
|
|
||||||
|
|
||||||
flags: 1 byte
|
|
||||||
optional padding: byte array of arbitrary size
|
|
||||||
payload: byte array of arbitrary size
|
|
||||||
optional signature: 65 bytes
|
|
||||||
|
|
||||||
Those unable to decrypt the message data are also unable to access the signature. The signature, if provided, is the ECDSA signature of the Keccak-256 hash of the unencrypted data using the secret key of the originator identity. The signature is serialised as the concatenation of the `R`, `S` and `V` parameters of the SECP-256k1 ECDSA signature, in that order. `R` and `S` are both big-endian encoded, fixed-width 256-bit unsigned. `V` is an 8-bit big-endian encoded, non-normalised and should be either 27 or 28.
|
|
||||||
|
|
||||||
The padding is introduced in order to align the message size, since message size alone might reveal important metainformation. The padding is supposed to contain random data (at least this is the default behaviour in version 5). However, it is possible to set arbitrary padding data, which might even be used for steganographic purposes. The API allows easy access to the padding data.
|
|
||||||
|
|
||||||
Default version 5 implementation ensures the size of the message to be multiple of 256. However, it is possible to set arbitrary padding through Whisper API. It might be useful for private Whisper networks, e.g. in order to ensure that all Whisper messages have the same (arbitrary) size. Incoming Whisper messages might have arbitrary padding size, and still be compatible with version 5.
|
|
||||||
|
|
||||||
The first several bytes of padding (up to four bytes) indicate the total size of padding. E.g. if padding is less than 256 bytes, then one byte is enough; if padding is less than 65536 bytes, then 2 bytes; and so on.
|
|
||||||
|
|
||||||
Flags byte uses only three bits in v.5. First two bits indicate, how many bytes indicate the padding size. The third byte indicates if signature is present. Other bits must be set to zero for backwards compatibility of future versions.
|
|
||||||
|
|
||||||
#### Topics
|
|
||||||
|
|
||||||
It might not be feasible to try to decrypt ALL incoming envelopes, because decryption is quite expensive. In order to facilitate the filtering, Topics were introduced to the Whisper protocol. Topic gives a probabilistic hint about encryption key. Single Topic corresponds to a single key (symmetric or asymmetric).
|
|
||||||
|
|
||||||
Upon receipt of a message, if the node detects a known Topic, it tries to decrypt the message with the corresponding key. In case of failure, the node assumes that Topic collision occurs, e.g. the message was encrypted with another key, and should be just forwarded further. Collisions are not only expected, they are necessary for plausible deniability.
|
|
||||||
|
|
||||||
Any Envelope could be encrypted only with one key, and therefore it contains only one Topic.
|
|
||||||
|
|
||||||
Topic field contains 4 bytes of arbitrary data. It might be generated from the key (e.g. first 4 bytes of the key hash), but we strongly discourage it. In order to avoid any compromise on security, Topics should be completely unrelated to the keys.
|
|
||||||
|
|
||||||
In order to use symmetric encryption, the nodes must exchange symmetric keys via some secure channel anyway. They might use the same channel in order to exchange the corresponding Topics as well.
|
|
||||||
|
|
||||||
In case of asymmetric encryption, it might be more complicated since public keys are meant to be exchanged via the open channels. So, the Ðapp has a choice of either publishing its Topic along with the public key (thus compromising on privacy), or trying to decrypt all asymmetrically encrypted Envelopes (at considerable expense). Alternatively, PoW requirement for asymmetric Envelopes might be set much higher than for symmetric ones, in order to limit the number of futile attempts.
|
|
||||||
|
|
||||||
It is also possible to publish a partial Topic (first bytes), and then filter the incoming messages correspondingly. In this case the sender should set the first bytes as required, and rest should be randomly generated.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
Partial Topic: 0x12 (first byte must be 0x12, the last three bytes - random)
|
|
||||||
Partial Topic: 0x1234 (first two bytes must be {0x12, 0x34}, the last two bytes - random)
|
|
||||||
Partial Topic: 0x123456 (first three bytes must be {0x12, 0x34, 0x56}, the last byte - random)
|
|
||||||
|
|
||||||
#### Filters
|
|
||||||
|
|
||||||
Any Ðapp can install multiple Filters utilising the Whisper API. Filters contain the secret key (symmetric or asymmetric), and some conditions, according to which the Filter should try to decrypt the incoming Envelopes. If Envelope does not satisfy those conditions, it should be ignored. Those are:
|
|
||||||
- array of possible Topics (or partial Topics)
|
|
||||||
- Sender address
|
|
||||||
- Recipient address
|
|
||||||
- PoW requirement
|
|
||||||
- AcceptP2P: boolean value, indicating whether the node accepts direct messages from trusted peers (reserved for some specific purposes, like Client/MailServer implementation)
|
|
||||||
|
|
||||||
All incoming messages, that have satisfied the Filter conditions AND have been successfully decrypted, will be saved by the corresponding Filter until the Ðapp requests them. Ðapps are expected to poll for incoming messages at regular time intervals. All installed Filters are independent of each other, and their conditions might overlap. If a message satisfies the conditions of multiple Filters, it will be stored in each of the Filters.
|
|
||||||
|
|
||||||
In future versions subscription will be used instead of polling.
|
|
||||||
|
|
||||||
In case of partial Topic, the message will match the Filter if first X bytes of the message Topic are equal to the corresponding bytes of partial Topic in Filter (where X can be 1, 2 or 3). The last bytes of the message Topic are ignored in this case.
|
|
||||||
|
|
||||||
#### Proof of Work
|
|
||||||
|
|
||||||
The purpose of PoW is spam prevention, and also reducing the burden on the network. The cost of computing PoW can be regarded as the price you pay for allocated resources if you want the network to store your message for a specific time (TTL). In terms of resources, it does not matter if the network stores X equal messages for Y seconds, or Y messages for X seconds. Or N messages of Z bytes each versus Z messages of N bytes. So, required PoW should be proportional to both message size and TTL.
|
|
||||||
|
|
||||||
After creating the Envelope, its Nonce should be repeatedly incremented, and then its hash should be calculated. This procedure could be run for a specific predefined time, looking for the lowest hash. Alternatively, the node might run the loop until certain predefined PoW is achieved.
|
|
||||||
|
|
||||||
In version 5, PoW is defined as average number of iterations, required to find the current BestBit (the number of leading zero bits in the hash), divided by message size and TTL:
|
|
||||||
|
|
||||||
<code>PoW = (2^BestBit) / (size * TTL)</code>
|
|
||||||
|
|
||||||
Thus, we can use PoW as a single aggregated parameter for the message rating. In the future versions every node will be able to set its own PoW requirement dynamically and communicate this change to the other nodes via the Whisper protocol. Now it is only possible to set PoW requirement at the Ðapp startup.
|
|
||||||
|
|
||||||
### Packet Codes (ÐΞVp2p level)
|
|
||||||
|
|
||||||
As a sub-protocol of [ÐΞVp2p](https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol), Whisper sends and receives its messages within ÐΞVp2p packets.
|
|
||||||
Whisper v5 supports the following packet codes:
|
|
||||||
|
|
||||||
<code>Status (0x0)</code>
|
|
||||||
|
|
||||||
<code>Messages (0x1)</code>
|
|
||||||
|
|
||||||
<code>P2PMessage (0x2)</code>
|
|
||||||
|
|
||||||
<code>P2PRequest (0x3)</code>
|
|
||||||
|
|
||||||
Also, the following codes might be supported in the future:
|
|
||||||
|
|
||||||
<code>PoWRequirement (0x4)</code>
|
|
||||||
|
|
||||||
<code>BloomFilterExchange (0x5)</code>
|
|
||||||
|
|
||||||
### Basic Operation
|
|
||||||
|
|
||||||
Nodes are expected to receive and send envelopes continuously. They should maintain a map of envelopes, indexed by expiry time, and prune accordingly. They should also efficiently deliver messages to the front-end API through maintaining mappings between Ðapps, their filters and envelopes.
|
|
||||||
|
|
||||||
When a node's envelope memory becomes exhausted, a node may drop envelopes it considers unimportant or unlikely to please its peers. Nodes should rate peers higher if they pass them envelopes with higher PoW. Nodes should blacklist peers if they pass invalid envelopes, i.e., expired envelopes or envelopes with an implied insertion time in the future.
|
|
||||||
|
|
||||||
Nodes should always treat messages that its ÐApps have created no different than incoming messages.
|
|
||||||
|
|
||||||
#### Creating and Sending Messages
|
|
||||||
|
|
||||||
To send a message, the node should place the envelope its envelope pool. Then this envelope will be forwarded to the peers in due course along with the other envelopes. Composing an envelope from a basic payload, is done in a few steps:
|
|
||||||
|
|
||||||
- Compose the Envelope data by concatenating the relevant flag byte, padding, payload (randomly generated or provided by user), and an optional signature.
|
|
||||||
- Encrypt the data symmetrically or asymmetrically.
|
|
||||||
- Add a Topic.
|
|
||||||
- Set the TTL attribute.
|
|
||||||
- Set the expiry as the present Unix time plus TTL.
|
|
||||||
- Set the nonce which provides the best PoW.
|
|
||||||
|
|
||||||
### Mail Server
|
|
||||||
|
|
||||||
Suppose, a Ðapp waits for messages with certain Topic and suffers an unexpected network failure for certain period of time. As a result, a number of important messages will be lost. Since those messages are expired, there is no way to resend them via the normal Whisper channels, because they will be rejected and the peer punished.
|
|
||||||
|
|
||||||
One possible way to solve this problem is to run a Mail Server, which would store all the messages, and resend them at the request of the known nodes. Even though the server might repack the old messages and provide sufficient PoW, it's not feasible to resend all of them at whim, because it would tantamount to DDoS attack on the entire network. Instead, the Mail Server should engage in peer-to-peer communication with the node, and resend the expired messages directly. The recipient will consume the messages and will not forward them any further.
|
|
||||||
|
|
||||||
In order to facilitate this task, protocol-level support is provided in version 5. New message types are introduced to Whisper v.5: mailRequestCode and p2pCode.
|
|
||||||
|
|
||||||
- mailRequestCode is used by the node to request historic (expired) messages from the Mail Server. The payload of this message should be understood by the Server. The Whisper protocol is entirely agnostic about it. It might contain a time frame, the node's authorization details, filtering information, payment details, etc.
|
|
||||||
|
|
||||||
- p2pCode is a peer-to-peer message, that is not supposed to be forwarded to other peers. It will also bypass the protocol-level checks for expiry and PoW threshold.
|
|
||||||
|
|
||||||
There is MailServer interface defined in the codebase for easy Mail Server implementation. One only needs to implement two functions:
|
|
||||||
|
|
||||||
type MailServer interface {
|
|
||||||
Archive(env *Envelope)
|
|
||||||
DeliverMail(whisperPeer *Peer, data []byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
Archive should just save all incoming messages.
|
|
||||||
DeliverMail should be able to process the request and send the historic messages to the corresponding peer (with p2pCode), according to additional information in the data parameter. This function will be invoked upon receipt of protocol-level mailRequestCode.
|
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
title: Whisper JavaScript example
|
|
||||||
---
|
|
||||||
|
|
||||||
[This link](https://github.com/gballet/whisper-chat-example) contains a full-fledged example of how to use Whisper in a small chat application.
|
|
||||||
|
|
||||||
Let's now have a look at the `sendMessage` function:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sendMessage() {
|
|
||||||
// Start by declaring the message, we picked a JSON format with
|
|
||||||
// `text` as the content and `name` as the name of the user who
|
|
||||||
// is sending the message.
|
|
||||||
let msg = {
|
|
||||||
text: this.text,
|
|
||||||
name: this.name
|
|
||||||
};
|
|
||||||
|
|
||||||
// (code elided for clarity)
|
|
||||||
|
|
||||||
// Create the data object that will be sent to the RPC endpoint.
|
|
||||||
let postData = {
|
|
||||||
ttl: 7,
|
|
||||||
topic: '0x07678231',
|
|
||||||
powTarget: 2.01,
|
|
||||||
powTime: 100,
|
|
||||||
payload: encodeToHex(JSON.stringify(msg)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the appropriate key id.
|
|
||||||
if (this.asym) {
|
|
||||||
postData.pubKey = this.recipientPubKey;
|
|
||||||
postData.sig = this.asymKeyId;
|
|
||||||
} else
|
|
||||||
postData.symKeyID = this.symKeyId;
|
|
||||||
|
|
||||||
// Perform the RPC call that will tell the node to forward
|
|
||||||
// that message to all its neighboring nodes.
|
|
||||||
this.shh.post(postData);
|
|
||||||
|
|
||||||
// (code elided for clarity)
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,785 +0,0 @@
|
||||||
---
|
|
||||||
title: Whisper RPC API 5.0
|
|
||||||
---
|
|
||||||
|
|
||||||
This is the proposed API for whisper v5.
|
|
||||||
|
|
||||||
### Specs
|
|
||||||
|
|
||||||
- [shh_version](#shh_version)
|
|
||||||
- [shh_info](#shh_info)
|
|
||||||
- [shh_setMaxMessageSize](#shh_setmaxmessagesize)
|
|
||||||
- [shh_setMinPoW](#shh_setminpow)
|
|
||||||
- [shh_markTrustedPeer](#shh_marktrustedpeer)
|
|
||||||
- [shh_newKeyPair](#shh_newkeypair)
|
|
||||||
- [shh_addPrivateKey](#shh_addprivatekey)
|
|
||||||
- [shh_deleteKeyPair](#shh_deletekeypair)
|
|
||||||
- [shh_hasKeyPair](#shh_haskeypair)
|
|
||||||
- [shh_getPublicKey](#shh_getpublickey)
|
|
||||||
- [shh_getPrivateKey](#shh_getprivatekey)
|
|
||||||
- [shh_newSymKey](#shh_newsymkey)
|
|
||||||
- [shh_addSymKey](#shh_addsymkey)
|
|
||||||
- [shh_generateSymKeyFromPassword](#shh_generatesymkeyfrompassword)
|
|
||||||
- [shh_hasSymKey](#shh_hassymkey)
|
|
||||||
- [shh_getSymKey](#shh_getsymkey)
|
|
||||||
- [shh_deleteSymKey](#shh_deletesymkey)
|
|
||||||
- [shh_subscribe](#shh_subscribe)
|
|
||||||
- [shh_unsubscribe](#shh_unsubscribe)
|
|
||||||
- [shh_newMessageFilter](#shh_newmessagefilter)
|
|
||||||
- [shh_deleteMessageFilter](#shh_deletemessagefilter)
|
|
||||||
- [shh_getFilterMessages](#shh_getfiltermessages)
|
|
||||||
- [shh_post](#shh_post)
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_version
|
|
||||||
|
|
||||||
Returns the current semver version number.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String` - The version number.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_version","params":[],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "5.0"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_info
|
|
||||||
|
|
||||||
Returns diagnostic information about the whisper node.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Object` - diagnostic information with the following properties:
|
|
||||||
- `minPow` - `Number`: current minimum PoW requirement.
|
|
||||||
- `maxMessageSize` - `Float`: current messgae size limit in bytes.
|
|
||||||
- `memory` - `Number`: Memory size of the floating messages in bytes.
|
|
||||||
- `messages` - `Number`: Number of floating messages.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_info","params":[],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": {
|
|
||||||
"minPow": 12.5,
|
|
||||||
"maxMessageSize": 20000,
|
|
||||||
"memory": 10000,
|
|
||||||
"messages": 20,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_setMaxMessageSize
|
|
||||||
|
|
||||||
Sets the maximal message size allowed by this node.
|
|
||||||
Incoming and outgoing messages with a larger size will be rejected.
|
|
||||||
Whisper message size can never exceed the limit imposed by the underlying P2P protocol (10 Mb).
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Number`: Message size in bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: (`true`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMaxMessageSize","params":[234567],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_setMinPoW
|
|
||||||
|
|
||||||
Sets the minimal PoW required by this node.
|
|
||||||
|
|
||||||
This experimental function was introduced for the future dynamic adjustment of PoW requirement. If the node is overwhelmed with messages, it should raise the PoW requirement and notify the peers. The new value should be set relative to the old value (e.g. double). The old value could be obtained via shh_info call.
|
|
||||||
|
|
||||||
**Note** This function is currently experimental.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Number`: The new PoW requirement.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMinPoW","params":[12.3],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_markTrustedPeer
|
|
||||||
|
|
||||||
Marks specific peer trusted, which will allow it to send historic (expired) messages.
|
|
||||||
|
|
||||||
**Note** This function is not adding new nodes, the node needs to exists as a peer.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: Enode of the trusted peer.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_markTrustedPeer","params":["enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_newKeyPair
|
|
||||||
|
|
||||||
Generates a new public and private key pair for message decryption and encryption.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newKeyPair","id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_addPrivateKey
|
|
||||||
|
|
||||||
Stores the key pair, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: private key as HEX bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addPrivateKey","params":["0x8bda3abeb454847b515fa9b404cede50b1cc63cfdeddd4999d074284b4c21e15"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "3e22b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteKeyPair
|
|
||||||
|
|
||||||
Deletes the specifies key if it exists.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_hasKeyPair
|
|
||||||
|
|
||||||
Checks if the whisper node has a private key of a key pair matching the given ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: (`true` or `false`) and error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": false
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getPublicKey
|
|
||||||
|
|
||||||
Returns the public key for identity ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Public key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPublicKey","params":["86e658cbc6da63120b79b5eec0c67d5dcfb6865a8f983eff08932477282b77bb"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0x04d1574d4eab8f3dde4d2dc7ed2c4d699d77cbbdd09167b8fffa099652ce4df00c4c6e0263eafe05007a46fdf0c8d32b11aeabcd3abbc7b2bc2bb967368a68e9c6"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getPrivateKey
|
|
||||||
|
|
||||||
Returns the private key for identity ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of the key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Private key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPrivateKey","params":["0xc862bf3cf4565d46abcbadaf4712a8940bfea729a91b9b0e338eab5166341ab5"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0x234234e22b9ffc2387e18636e0534534a3d0c56b0243567432453264c16e78a2adc"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_newSymKey
|
|
||||||
|
|
||||||
Generates a random symmetric key and stores it under an ID, which is then returned.
|
|
||||||
Can be used encrypting and decrypting messages where the key is known to both parties.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newSymKey", "params": [], "id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "cec94d139ff51d7df1d228812b90c23ec1f909afa0840ed80f1e04030bb681e4"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_addSymKey
|
|
||||||
|
|
||||||
Stores the key, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: The raw key for symmetric encryption as HEX bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addSymKey","params":["0xf6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_generateSymKeyFromPassword
|
|
||||||
|
|
||||||
Generates the key from password, stores it, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: password.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_generateSymKeyFromPassword","params":["test"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "2e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_hasSymKey
|
|
||||||
|
|
||||||
Returns true if there is a key associated with the name string. Otherwise, returns false.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getSymKey
|
|
||||||
|
|
||||||
Returns the symmetric key associated with the given ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Raw key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0xa82a520aff70f7a989098376e48ec128f25f767085e84d7fb995a9815eebff0a"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteSymKey
|
|
||||||
|
|
||||||
Deletes the key associated with the name string if it exists.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteSymKey","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_subscribe
|
|
||||||
|
|
||||||
Creates and registers a new subscription to receive notifications for inbound whisper messages. Returns the ID of the newly created subscription.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: identifier of function call. In case of Whisper must contain the value "messages".
|
|
||||||
|
|
||||||
2. `Object`. Options object with the following properties:
|
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message decryption.
|
|
||||||
- `privateKeyID` - `String`: ID of private (asymmetric) key for message decryption.
|
|
||||||
- `sig` - `String` (optional): Public key of the signature.
|
|
||||||
- `minPow` - `Number` (optional): Minimal PoW requirement for incoming messages.
|
|
||||||
- `topics` - `Array` (optional when asym key): Array of possible topics (or partial topics).
|
|
||||||
- `allowP2P` - `Boolean` (optional): Indicates if this filter allows processing of direct peer-to-peer messages (which are not to be forwarded any further, because they might be expired). This might be the case in some very rare cases, e.g. if you intend to communicate to MailServers, etc.
|
|
||||||
|
|
||||||
Either `symKeyID` or `privateKeyID` must be present. Can not be both.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String` - The subscription ID on success, the error on failure.
|
|
||||||
|
|
||||||
|
|
||||||
##### Notification Return
|
|
||||||
|
|
||||||
`Object`: The whisper message matching the subscription options, with the following parameters:
|
|
||||||
- `sig` - `String`: Public key who signed this message.
|
|
||||||
- `recipientPublicKey` - `String`: The recipients public key.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message genertion.
|
|
||||||
- `topic` - `String` 4 Bytes: Message topic.
|
|
||||||
- `payload` - `String`: Decrypted payload.
|
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length).
|
|
||||||
- `pow` - `Number`: Proof of work value.
|
|
||||||
- `hash` - `String`: Hash of the enveloved message.
|
|
||||||
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_subscribe","params":["messages", {
|
|
||||||
topics: ['0x5a4ea131', '0x11223344'],
|
|
||||||
symKeyID: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea',
|
|
||||||
sig: '0x048229fb947363cf13bb9f9532e124f08840cd6287ecae6b537cda2947ec2b23dbdc3a07bdf7cd2bfb288c25c4d0d0461d91c719da736a22b7bebbcf912298d1e6',
|
|
||||||
pow: 12.3(?)
|
|
||||||
}],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Notification Result
|
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "shh_subscription",
|
|
||||||
"params": {
|
|
||||||
subscription: "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412",
|
|
||||||
result: {
|
|
||||||
sig: '0x0498ac1951b9078a0549c93c3f6088ec7c790032b17580dc3c0c9e900899a48d89eaa27471e3071d2de6a1f48716ecad8b88ee022f4321a7c29b6ffcbee65624ff',
|
|
||||||
recipientPublicKey: null,
|
|
||||||
ttl: 10,
|
|
||||||
timestamp: 1498577270,
|
|
||||||
topic: '0xffaadd11',
|
|
||||||
payload: '0xffffffdddddd1122',
|
|
||||||
padding: '0x35d017b66b124dd4c67623ed0e3f23ba68e3428aa500f77aceb0dbf4b63f69ccfc7ae11e39671d7c94f1ed170193aa3e327158dffdd7abb888b3a3cc48f718773dc0a9dcf1a3680d00fe17ecd4e8d5db31eb9a3c8e6e329d181ecb6ab29eb7a2d9889b49201d9923e6fd99f03807b730780a58924870f541a8a97c87533b1362646e5f573dc48382ef1e70fa19788613c9d2334df3b613f6e024cd7aadc67f681fda6b7a84efdea40cb907371cd3735f9326d02854',
|
|
||||||
pow: 0.6714754098360656,
|
|
||||||
hash: '0x17f8066f0540210cf67ef400a8a55bcb32a494a47f91a0d26611c5c1d66f8c57'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_unsubscribe
|
|
||||||
|
|
||||||
Cancels and removes an existing subscription.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: subscription ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` or `false`.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_unsubscribe","params":["02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_newMessageFilter
|
|
||||||
|
|
||||||
Create a new filter within the node. This filter can be used to poll for new messages that match the set of criteria.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `criteria` - `Object`: see [shh_subscribe](#shh_subscribe)
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: filter identifier
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{"jsonrpc":"2.0","id":1,"result":"2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteMessageFilter
|
|
||||||
|
|
||||||
Uninstall a message filter in the node
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: filter identifier as returned when the filter was created
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success, error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{"jsonrpc":"2.0","id":1,"result": true}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getFilterMessages
|
|
||||||
|
|
||||||
Retrieve messages that match the filter criteria and are received between the last time this
|
|
||||||
function was called and now.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: ID of filter that was created with `shh_newMessageFilter`
|
|
||||||
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Array of messages`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
`Object`: whisper message:
|
|
||||||
- `sig` - `String`: Public key who signed this message.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message generation.
|
|
||||||
- `topic` - `String` 4 Bytes: Message topic.
|
|
||||||
- `payload` - `String`: Decrypted payload.
|
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length).
|
|
||||||
- `pow` - `Number`: Proof of work value.
|
|
||||||
- `hash` - `String`: Hash of the enveloped message.
|
|
||||||
- `recipientPublicKey` - `String`: recipient public key
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getFilterMessages","params":["2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": [
|
|
||||||
{
|
|
||||||
"hash": "0xe05c4be74d667bd4c57dba2a8dbfb097d6fc2719d5c0d699d2f84a2442a4d8c2",
|
|
||||||
"padding": "0x6e3e82571c7aa91f2a9e82e20344ede0d1112205555843d9dafffeb1536741a1fca758ff30cc01320bb0775aa5b82b9c9f48deb10bff8b5c61354bf8f95f2ab7289c7894c52e285b1d750ea2ffa78edd374bc7386a901d36a59022d73208c852dedaca8709087693ef6831b861139f42a89263af5931cb2b9253216dc42edc1393afd03940f91c561d20080f7a258aa52d30dcf4b1b921b7c910ad429f73ed9308cb6218537f0444d915e993ba8c9bb00af311aab3574bf1722b5640632bf5bb6b12406e1b89d0c98628117b1d8f55ea6b974e251b34969d4c49dfb6036d40e0d90414c65a8b036ae985396d6a4bf28332676e85dc0a0d352a58680200cc",
|
|
||||||
"payload": "0xabcd",
|
|
||||||
"pow": 0.5371803278688525,
|
|
||||||
"recipientPublicKey": null,
|
|
||||||
"sig": null,
|
|
||||||
"timestamp": 1496991875,
|
|
||||||
"topic": "0x01020304",
|
|
||||||
"ttl": 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hash": "0x4158eb81ad8e30cfcee67f20b1372983d388f1243a96e39f94fd2797b1e9c78e",
|
|
||||||
"padding": "0xc15f786f34e5cef0fef6ce7c1185d799ecdb5ebca72b3310648c5588db2e99a0d73301c7a8d90115a91213f0bc9c72295fbaf584bf14dc97800550ea53577c9fb57c0249caeb081733b4e605cdb1a6011cee8b6d8fddb972c2b90157e23ba3baae6c68d4f0b5822242bb2c4cd821b9568d3033f10ec1114f641668fc1083bf79ebb9f5c15457b538249a97b22a4bcc4f02f06dec7318c16758f7c008001c2e14eba67d26218ec7502ad6ba81b2402159d7c29b068b8937892e3d4f0d4ad1fb9be5e66fb61d3d21a1c3163bce74c0a9d16891e2573146aa92ecd7b91ea96a6987ece052edc5ffb620a8987a83ac5b8b6140d8df6e92e64251bf3a2cec0cca",
|
|
||||||
"payload": "0xdeadbeaf",
|
|
||||||
"pow": 0.5371803278688525,
|
|
||||||
"recipientPublicKey": null,
|
|
||||||
"sig": null,
|
|
||||||
"timestamp": 1496991876,
|
|
||||||
"topic": "0x01020304",
|
|
||||||
"ttl": 50
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_post
|
|
||||||
|
|
||||||
Creates a whisper message and injects it into the network for distribution.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Object`. Post options object with the following properties:
|
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message encryption.
|
|
||||||
- `pubKey` - `String`: public key for message encryption.
|
|
||||||
- `sig` - `String` (optional): ID of the signing key.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `topic` - `String` 4 Bytes (mandatory when key is symmetric): Message topic.
|
|
||||||
- `payload` - `String`: Payload to be encrypted.
|
|
||||||
- `padding` - `String` (optional): Optional padding (byte array of arbitrary length).
|
|
||||||
- `powTime` - `Number`: Maximal time in seconds to be spent on proof of work.
|
|
||||||
- `powTarget` - `Number`: Minimal PoW target required for this message.
|
|
||||||
- `targetPeer` - `String` (optional): Optional peer ID (for peer-to-peer message only).
|
|
||||||
|
|
||||||
Either `symKeyID` or `pubKey` must be present. Can not be both.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_post","params":[{
|
|
||||||
pubKey: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea',
|
|
||||||
ttl: 7,
|
|
||||||
topic: '0x07678231',
|
|
||||||
powTarget: 2.01,
|
|
||||||
powTime: 2,
|
|
||||||
payload: '0x68656c6c6f'
|
|
||||||
}],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,785 +0,0 @@
|
||||||
---
|
|
||||||
title: Whisper RPC API 6.0
|
|
||||||
---
|
|
||||||
|
|
||||||
This is the proposed API for whisper v6.
|
|
||||||
|
|
||||||
### Specs
|
|
||||||
|
|
||||||
- [shh_version](#shh_version)
|
|
||||||
- [shh_info](#shh_info)
|
|
||||||
- [shh_setMaxMessageSize](#shh_setmaxmessagesize)
|
|
||||||
- [shh_setMinPoW](#shh_setminpow)
|
|
||||||
- [shh_markTrustedPeer](#shh_marktrustedpeer)
|
|
||||||
- [shh_newKeyPair](#shh_newkeypair)
|
|
||||||
- [shh_addPrivateKey](#shh_addprivatekey)
|
|
||||||
- [shh_deleteKeyPair](#shh_deletekeypair)
|
|
||||||
- [shh_hasKeyPair](#shh_haskeypair)
|
|
||||||
- [shh_getPublicKey](#shh_getpublickey)
|
|
||||||
- [shh_getPrivateKey](#shh_getprivatekey)
|
|
||||||
- [shh_newSymKey](#shh_newsymkey)
|
|
||||||
- [shh_addSymKey](#shh_addsymkey)
|
|
||||||
- [shh_generateSymKeyFromPassword](#shh_generatesymkeyfrompassword)
|
|
||||||
- [shh_hasSymKey](#shh_hassymkey)
|
|
||||||
- [shh_getSymKey](#shh_getsymkey)
|
|
||||||
- [shh_deleteSymKey](#shh_deletesymkey)
|
|
||||||
- [shh_subscribe](#shh_subscribe)
|
|
||||||
- [shh_unsubscribe](#shh_unsubscribe)
|
|
||||||
- [shh_newMessageFilter](#shh_newmessagefilter)
|
|
||||||
- [shh_deleteMessageFilter](#shh_deletemessagefilter)
|
|
||||||
- [shh_getFilterMessages](#shh_getfiltermessages)
|
|
||||||
- [shh_post](#shh_post)
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_version
|
|
||||||
|
|
||||||
Returns the current semver version number.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String` - The version number.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_version","params":[],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "6.0"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_info
|
|
||||||
|
|
||||||
Returns diagnostic information about the whisper node.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Object` - diagnostic information with the following properties:
|
|
||||||
- `minPow` - `Number`: current minimum PoW requirement.
|
|
||||||
- `maxMessageSize` - `Float`: current messgae size limit in bytes.
|
|
||||||
- `memory` - `Number`: Memory size of the floating messages in bytes.
|
|
||||||
- `messages` - `Number`: Number of floating messages.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_info","params":[],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": {
|
|
||||||
"minPow": 12.5,
|
|
||||||
"maxMessageSize": 20000,
|
|
||||||
"memory": 10000,
|
|
||||||
"messages": 20,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_setMaxMessageSize
|
|
||||||
|
|
||||||
Sets the maximal message size allowed by this node.
|
|
||||||
Incoming and outgoing messages with a larger size will be rejected.
|
|
||||||
Whisper message size can never exceed the limit imposed by the underlying P2P protocol (10 Mb).
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Number`: Message size in bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: (`true`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMaxMessageSize","params":[234567],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_setMinPoW
|
|
||||||
|
|
||||||
Sets the minimal PoW required by this node.
|
|
||||||
|
|
||||||
This experimental function was introduced for the future dynamic adjustment of PoW requirement. If the node is overwhelmed with messages, it should raise the PoW requirement and notify the peers. The new value should be set relative to the old value (e.g. double). The old value could be obtained via shh_info call.
|
|
||||||
|
|
||||||
**Note** This function is currently experimental.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Number`: The new PoW requirement.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMinPoW","params":[12.3],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_markTrustedPeer
|
|
||||||
|
|
||||||
Marks specific peer trusted, which will allow it to send historic (expired) messages.
|
|
||||||
|
|
||||||
**Note** This function is not adding new nodes, the node needs to exists as a peer.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: Enode of the trusted peer.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_markTrustedPeer","params":["enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_newKeyPair
|
|
||||||
|
|
||||||
Generates a new public and private key pair for message decryption and encryption.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newKeyPair","id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_addPrivateKey
|
|
||||||
|
|
||||||
Stores the key pair, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: private key as HEX bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addPrivateKey","params":["0x8bda3abeb454847b515fa9b404cede50b1cc63cfdeddd4999d074284b4c21e15"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "3e22b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteKeyPair
|
|
||||||
|
|
||||||
Deletes the specifies key if it exists.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
|
|
||||||
#### shh_hasKeyPair
|
|
||||||
|
|
||||||
Checks if the whisper node has a private key of a key pair matching the given ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: (`true` or `false`) and error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": false
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getPublicKey
|
|
||||||
|
|
||||||
Returns the public key for identity ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Public key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPublicKey","params":["86e658cbc6da63120b79b5eec0c67d5dcfb6865a8f983eff08932477282b77bb"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0x04d1574d4eab8f3dde4d2dc7ed2c4d699d77cbbdd09167b8fffa099652ce4df00c4c6e0263eafe05007a46fdf0c8d32b11aeabcd3abbc7b2bc2bb967368a68e9c6"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getPrivateKey
|
|
||||||
|
|
||||||
Returns the private key for identity ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: ID of the key pair.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Private key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPrivateKey","params":["0xc862bf3cf4565d46abcbadaf4712a8940bfea729a91b9b0e338eab5166341ab5"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0x234234e22b9ffc2387e18636e0534534a3d0c56b0243567432453264c16e78a2adc"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_newSymKey
|
|
||||||
|
|
||||||
Generates a random symmetric key and stores it under an ID, which is then returned.
|
|
||||||
Can be used encrypting and decrypting messages where the key is known to both parties.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
none
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newSymKey", "params": [], "id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "cec94d139ff51d7df1d228812b90c23ec1f909afa0840ed80f1e04030bb681e4"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_addSymKey
|
|
||||||
|
|
||||||
Stores the key, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: The raw key for symmetric encryption as HEX bytes.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addSymKey","params":["0xf6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_generateSymKeyFromPassword
|
|
||||||
|
|
||||||
Generates the key from password, stores it, and returns its ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: password.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_generateSymKeyFromPassword","params":["test"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "2e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_hasSymKey
|
|
||||||
|
|
||||||
Returns true if there is a key associated with the name string. Otherwise, returns false.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getSymKey
|
|
||||||
|
|
||||||
Returns the symmetric key associated with the given ID.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: Raw key on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "0xa82a520aff70f7a989098376e48ec128f25f767085e84d7fb995a9815eebff0a"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteSymKey
|
|
||||||
|
|
||||||
Deletes the key associated with the name string if it exists.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: key ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteSymKey","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_subscribe
|
|
||||||
|
|
||||||
Creates and registers a new subscription to receive notifications for inbound whisper messages. Returns the ID of the newly created subscription.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: identifier of function call. In case of Whisper must contain the value "messages".
|
|
||||||
|
|
||||||
2. `Object`. Options object with the following properties:
|
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message decryption.
|
|
||||||
- `privateKeyID` - `String`: ID of private (asymmetric) key for message decryption.
|
|
||||||
- `sig` - `String` (optional): Public key of the signature.
|
|
||||||
- `minPow` - `Number` (optional): Minimal PoW requirement for incoming messages.
|
|
||||||
- `topics` - `Array` (optional when asym key): Array of possible topics (or partial topics).
|
|
||||||
- `allowP2P` - `Boolean` (optional): Indicates if this filter allows processing of direct peer-to-peer messages (which are not to be forwarded any further, because they might be expired). This might be the case in some very rare cases, e.g. if you intend to communicate to MailServers, etc.
|
|
||||||
|
|
||||||
Either `symKeyID` or `privateKeyID` must be present. Can not be both.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String` - The subscription ID on success, the error on failure.
|
|
||||||
|
|
||||||
|
|
||||||
##### Notification Return
|
|
||||||
|
|
||||||
`Object`: The whisper message matching the subscription options, with the following parameters:
|
|
||||||
- `sig` - `String`: Public key who signed this message.
|
|
||||||
- `recipientPublicKey` - `String`: The recipients public key.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message genertion.
|
|
||||||
- `topic` - `String` 4 Bytes: Message topic.
|
|
||||||
- `payload` - `String`: Decrypted payload.
|
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length).
|
|
||||||
- `pow` - `Number`: Proof of work value.
|
|
||||||
- `hash` - `String`: Hash of the enveloved message.
|
|
||||||
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_subscribe","params":["messages", {
|
|
||||||
topics: ['0x5a4ea131', '0x11223344'],
|
|
||||||
symKeyID: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea',
|
|
||||||
sig: '0x048229fb947363cf13bb9f9532e124f08840cd6287ecae6b537cda2947ec2b23dbdc3a07bdf7cd2bfb288c25c4d0d0461d91c719da736a22b7bebbcf912298d1e6',
|
|
||||||
pow: 12.3(?)
|
|
||||||
}],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Notification Result
|
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "shh_subscription",
|
|
||||||
"params": {
|
|
||||||
subscription: "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412",
|
|
||||||
result: {
|
|
||||||
sig: '0x0498ac1951b9078a0549c93c3f6088ec7c790032b17580dc3c0c9e900899a48d89eaa27471e3071d2de6a1f48716ecad8b88ee022f4321a7c29b6ffcbee65624ff',
|
|
||||||
recipientPublicKey: null,
|
|
||||||
ttl: 10,
|
|
||||||
timestamp: 1498577270,
|
|
||||||
topic: '0xffaadd11',
|
|
||||||
payload: '0xffffffdddddd1122',
|
|
||||||
padding: '0x35d017b66b124dd4c67623ed0e3f23ba68e3428aa500f77aceb0dbf4b63f69ccfc7ae11e39671d7c94f1ed170193aa3e327158dffdd7abb888b3a3cc48f718773dc0a9dcf1a3680d00fe17ecd4e8d5db31eb9a3c8e6e329d181ecb6ab29eb7a2d9889b49201d9923e6fd99f03807b730780a58924870f541a8a97c87533b1362646e5f573dc48382ef1e70fa19788613c9d2334df3b613f6e024cd7aadc67f681fda6b7a84efdea40cb907371cd3735f9326d02854',
|
|
||||||
pow: 0.6714754098360656,
|
|
||||||
hash: '0x17f8066f0540210cf67ef400a8a55bcb32a494a47f91a0d26611c5c1d66f8c57'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_unsubscribe
|
|
||||||
|
|
||||||
Cancels and removes an existing subscription.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `String`: subscription ID.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` or `false`.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```js
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_unsubscribe","params":["02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_newMessageFilter
|
|
||||||
|
|
||||||
Create a new filter within the node. This filter can be used to poll for new messages that match the set of criteria.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `criteria` - `Object`: see [shh_subscribe](#shh_subscribe)
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`String`: filter identifier
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{"jsonrpc":"2.0","id":1,"result":"2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_deleteMessageFilter
|
|
||||||
|
|
||||||
Uninstall a message filter in the node
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: filter identifier as returned when the filter was created
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success, error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{"jsonrpc":"2.0","id":1,"result": true}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_getFilterMessages
|
|
||||||
|
|
||||||
Retrieve messages that match the filter criteria and are received between the last time this
|
|
||||||
function was called and now.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `id` - `String`: ID of filter that was created with `shh_newMessageFilter`
|
|
||||||
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Array of messages`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
`Object`: whisper message:
|
|
||||||
- `sig` - `String`: Public key who signed this message.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message generation.
|
|
||||||
- `topic` - `String` 4 Bytes: Message topic.
|
|
||||||
- `payload` - `String`: Decrypted payload.
|
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length).
|
|
||||||
- `pow` - `Number`: Proof of work value.
|
|
||||||
- `hash` - `String`: Hash of the enveloped message.
|
|
||||||
- `recipientPublicKey` - `String`: recipient public key
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getFilterMessages","params":["2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": [
|
|
||||||
{
|
|
||||||
"hash": "0xe05c4be74d667bd4c57dba2a8dbfb097d6fc2719d5c0d699d2f84a2442a4d8c2",
|
|
||||||
"padding": "0x6e3e82571c7aa91f2a9e82e20344ede0d1112205555843d9dafffeb1536741a1fca758ff30cc01320bb0775aa5b82b9c9f48deb10bff8b5c61354bf8f95f2ab7289c7894c52e285b1d750ea2ffa78edd374bc7386a901d36a59022d73208c852dedaca8709087693ef6831b861139f42a89263af5931cb2b9253216dc42edc1393afd03940f91c561d20080f7a258aa52d30dcf4b1b921b7c910ad429f73ed9308cb6218537f0444d915e993ba8c9bb00af311aab3574bf1722b5640632bf5bb6b12406e1b89d0c98628117b1d8f55ea6b974e251b34969d4c49dfb6036d40e0d90414c65a8b036ae985396d6a4bf28332676e85dc0a0d352a58680200cc",
|
|
||||||
"payload": "0xabcd",
|
|
||||||
"pow": 0.5371803278688525,
|
|
||||||
"recipientPublicKey": null,
|
|
||||||
"sig": null,
|
|
||||||
"timestamp": 1496991875,
|
|
||||||
"topic": "0x01020304",
|
|
||||||
"ttl": 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hash": "0x4158eb81ad8e30cfcee67f20b1372983d388f1243a96e39f94fd2797b1e9c78e",
|
|
||||||
"padding": "0xc15f786f34e5cef0fef6ce7c1185d799ecdb5ebca72b3310648c5588db2e99a0d73301c7a8d90115a91213f0bc9c72295fbaf584bf14dc97800550ea53577c9fb57c0249caeb081733b4e605cdb1a6011cee8b6d8fddb972c2b90157e23ba3baae6c68d4f0b5822242bb2c4cd821b9568d3033f10ec1114f641668fc1083bf79ebb9f5c15457b538249a97b22a4bcc4f02f06dec7318c16758f7c008001c2e14eba67d26218ec7502ad6ba81b2402159d7c29b068b8937892e3d4f0d4ad1fb9be5e66fb61d3d21a1c3163bce74c0a9d16891e2573146aa92ecd7b91ea96a6987ece052edc5ffb620a8987a83ac5b8b6140d8df6e92e64251bf3a2cec0cca",
|
|
||||||
"payload": "0xdeadbeaf",
|
|
||||||
"pow": 0.5371803278688525,
|
|
||||||
"recipientPublicKey": null,
|
|
||||||
"sig": null,
|
|
||||||
"timestamp": 1496991876,
|
|
||||||
"topic": "0x01020304",
|
|
||||||
"ttl": 50
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
#### shh_post
|
|
||||||
|
|
||||||
Creates a whisper message and injects it into the network for distribution.
|
|
||||||
|
|
||||||
##### Parameters
|
|
||||||
|
|
||||||
1. `Object`. Post options object with the following properties:
|
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message encryption.
|
|
||||||
- `pubKey` - `String`: public key for message encryption.
|
|
||||||
- `sig` - `String` (optional): ID of the signing key.
|
|
||||||
- `ttl` - `Number`: Time-to-live in seconds.
|
|
||||||
- `topic` - `String` 4 Bytes (mandatory when key is symmetric): Message topic.
|
|
||||||
- `payload` - `String`: Payload to be encrypted.
|
|
||||||
- `padding` - `String` (optional): Optional padding (byte array of arbitrary length).
|
|
||||||
- `powTime` - `Number`: Maximal time in seconds to be spent on proof of work.
|
|
||||||
- `powTarget` - `Number`: Minimal PoW target required for this message.
|
|
||||||
- `targetPeer` - `String` (optional): Optional peer ID (for peer-to-peer message only).
|
|
||||||
|
|
||||||
Either `symKeyID` or `pubKey` must be present. Can not be both.
|
|
||||||
|
|
||||||
##### Returns
|
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure.
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```
|
|
||||||
// Request
|
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_post","params":[{
|
|
||||||
pubKey: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea',
|
|
||||||
ttl: 7,
|
|
||||||
topic: '0x07678231',
|
|
||||||
powTarget: 2.01,
|
|
||||||
powTime: 2,
|
|
||||||
payload: '0x68656c6c6f'
|
|
||||||
}],"id":1}'
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": true
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,21 +0,0 @@
|
||||||
---
|
|
||||||
title: Whisper v6
|
|
||||||
---
|
|
||||||
|
|
||||||
[Whisper Overview](Whisper-Overview)
|
|
||||||
|
|
||||||
[Whisper web3.js API Documentation](http://web3js.readthedocs.io/en/1.0/web3-shh.html)
|
|
||||||
|
|
||||||
[Whisper RPC API 6.0](Whisper-v6-RPC-API)
|
|
||||||
|
|
||||||
[Diagnostic Tool wnode](Diagnostic-Tool-wnode)
|
|
||||||
|
|
||||||
[Achieving Darkness](Achieving-Darkness)
|
|
||||||
|
|
||||||
[Javascript Example](Whisper-js-example)
|
|
||||||
|
|
||||||
## Legacy documentation (unsupported)
|
|
||||||
|
|
||||||
Whisper v2 to v5 are no longer supported.
|
|
||||||
|
|
||||||
[Whisper RPC API 5.0](Whisper-v5-RPC-API)
|
|
|
@ -1,111 +0,0 @@
|
||||||
---
|
|
||||||
title: Geth
|
|
||||||
---
|
|
||||||
`geth` is the the command line interface for running a full ethereum node implemented in Go.
|
|
||||||
It is the main deliverable of the [Frontier Release](https://ethereum.gitbooks.io/frontier-guide/content/frontier.html)
|
|
||||||
|
|
||||||
## Capabilities
|
|
||||||
|
|
||||||
By installing and running `geth`, you can take part in the ethereum frontier live network and
|
|
||||||
* mine real ether
|
|
||||||
* transfer funds between addresses
|
|
||||||
* create contracts and send transactions
|
|
||||||
* explore block history
|
|
||||||
* and much much more
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Supported Platforms are Linux, Mac Os and Windows.
|
|
||||||
|
|
||||||
We support two types of installation: binary or scripted install for users.
|
|
||||||
See [Install instructions](../install-and-build/Building-Ethereum) for binary and scripted installs.
|
|
||||||
|
|
||||||
Developers and community enthusiast are advised to read the [Developers' Guide](../install-and-build/Developers-Guide), which contains detailed instructions for manual build from source (on any platform) as well as detailed tips on testing, monitoring, contributing, debugging and submitting pull requests on github.
|
|
||||||
|
|
||||||
## Interfaces
|
|
||||||
|
|
||||||
* Javascript Console: `geth` can be launched with an interactive console, that provides a javascript runtime environment exposing a javascript API to interact with your node. [Javascript Console API](../interface/JavaScript-Console) includes the `web3` javascript Ðapp API as well as an additional admin API.
|
|
||||||
* JSON-RPC server: `geth` can be launched with a json-rpc server that exposes the [JSON-RPC API](https://github.com/ethereum/wiki/JSON-RPC)
|
|
||||||
* [Command line options](../interface/Command-Line-Options) documents command line parameters as well as subcommands.
|
|
||||||
|
|
||||||
## Basic Use Case Documentation
|
|
||||||
|
|
||||||
* [Managing accounts](../how-to/Managing-your-accounts)
|
|
||||||
* [Mining](../how-to/Mining)
|
|
||||||
|
|
||||||
**Note** buying and selling ether through exchanges is not discussed here.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The Ethereum Core Protocol licensed under the [GNU Lesser General Public License](https://www.gnu.org/licenses/lgpl.html). All frontend client software (under [cmd](https://github.com/ethereum/go-ethereum/tree/develop/cmd)) is licensed under the [GNU General Public License](https://www.gnu.org/copyleft/gpl.html).
|
|
||||||
|
|
||||||
## Reporting
|
|
||||||
|
|
||||||
Security issues are best sent to security@ethereum.org or shared in PM with devs on one of the channels (see Community and Suppport).
|
|
||||||
|
|
||||||
Non-sensitive bug reports are welcome on github. Please always state the version (on master) or commit of your build (if on develop), give as much detail as possible about the situation and the anomaly that occurred. Provide logs or stacktrace if you can.
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
Ethereum is joint work of ETHDEV and the community.
|
|
||||||
|
|
||||||
Name or blame = list of contributors:
|
|
||||||
* [go-ethereum](https://github.com/ethereum/go-ethereum/graphs/contributors)
|
|
||||||
* [cpp-ethereum](https://github.com/ethereum/cpp-ethereum/graphs/contributors)
|
|
||||||
* [web3.js](https://github.com/ethereum/web3.js/graphs/contributors)
|
|
||||||
* [ethash](https://github.com/ethereum/ethash/graphs/contributors)
|
|
||||||
* [netstats](https://github.com/cubedro/eth-netstats/graphs/contributors),
|
|
||||||
[netintelligence-api](https://github.com/cubedro/eth-net-intelligence-api/graphs/contributors)
|
|
||||||
|
|
||||||
## Community and support
|
|
||||||
|
|
||||||
### Ethereum on social media
|
|
||||||
|
|
||||||
- Main site: https://www.ethereum.org
|
|
||||||
- Forum: https://forum.ethereum.org
|
|
||||||
- Github: https://github.com/ethereum
|
|
||||||
- Blog: https://blog.ethereum.org
|
|
||||||
- Wiki: http://wiki.ethereum.org
|
|
||||||
- Twitter: http://twitter.com/ethereumproject
|
|
||||||
- Reddit: http://reddit.com/r/ethereum
|
|
||||||
- Meetups: http://ethereum.meetup.com
|
|
||||||
- Facebook: https://www.facebook.com/ethereumproject
|
|
||||||
- Youtube: http://www.youtube.com/ethereumproject
|
|
||||||
- Google+: http://google.com/+EthereumOrgOfficial
|
|
||||||
|
|
||||||
### IRC
|
|
||||||
|
|
||||||
IRC Freenode channels:
|
|
||||||
* `#ethereum`: for general discussion
|
|
||||||
* `#ethereum-dev`: for development specific questions and discussions
|
|
||||||
* `##ethereum`: for offtopic and banter
|
|
||||||
* `#ethereumjs`: for questions related to web3.js and node-ethereum
|
|
||||||
* `#ethereum-markets`: Trading
|
|
||||||
* `#ethereum-mining` Mining
|
|
||||||
* `#dappdevs`: Dapp developers channel
|
|
||||||
* `#ethdev`: buildserver etc
|
|
||||||
|
|
||||||
[IRC Logs by ZeroGox](https://zerogox.com/bot/log)
|
|
||||||
|
|
||||||
### Gitter
|
|
||||||
|
|
||||||
* [go-ethereum Gitter](https://gitter.im/ethereum/go-ethereum)
|
|
||||||
* [cpp-ethereum Gitter](https://gitter.im/ethereum/cpp-ethereum)
|
|
||||||
* [web3.js Gitter](https://gitter.im/ethereum/web3.js)
|
|
||||||
* [ethereum documentation project Gitter](https://gitter.im/ethereum/frontier-guide)
|
|
||||||
|
|
||||||
### Forum
|
|
||||||
|
|
||||||
- [Forum](https://forum.ethereum.org/categories/go-implementation)
|
|
||||||
|
|
||||||
### The ZeroGox Bot
|
|
||||||
|
|
||||||
[ZeroGox Bot](https://zerogox.com/bot)
|
|
||||||
|
|
||||||
### Dapp developers' mailing list
|
|
||||||
|
|
||||||
https://dapplist.net/
|
|
||||||
|
|
||||||
### Helpdesk
|
|
||||||
|
|
||||||
On gitter, irc, skype or mail to helpdesk@ethereum.org
|
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
title: Swarm POC series
|
|
||||||
---
|
|
||||||
now project features and POC milestones are managed under
|
|
||||||
https://github.com/ethereum/go-ethereum/projects/6
|
|
||||||
|
|
||||||
## POC 0.1: plan bee
|
|
||||||
|
|
||||||
* [x] underground dev testnet launched on BZZ day (3.22 is l33t for BZZ)
|
|
||||||
* [x] create ansible and docker for node deployment
|
|
||||||
* [x] a few public gateways
|
|
||||||
|
|
||||||
## POC 0.2 sworm
|
|
||||||
|
|
||||||
* [x] rebase on geth 1.5 edge
|
|
||||||
* [x] small toynet deployed, see [network monitor](http://146.185.130.117/)
|
|
||||||
* [x] support for separate url schemes for dns enabled, immutable and raw manifest - feature [#2279](https://github.com/ethereum/go-ethereum/issues/2279)
|
|
||||||
* [x] Ethereum name service integration
|
|
||||||
* [x] scripted network tests, cluster control framework
|
|
||||||
* [x] algorithmic improvements on chunker split/join
|
|
||||||
* [x] algorithmic improvements on upload/download
|
|
||||||
* [x] algorithmic improvements in kademlia and hive peers manager
|
|
||||||
* [x] calibrating kademlia connectivity parameters to toynet scale
|
|
||||||
* [x] orange paper series released hosted on [swarm toynet](http://swarm-gateways.net/bzz:/swarm#the-thsphr-orange-papers)
|
|
||||||
* [x] minimalistic [swarm homepage](http://swarm-gateways.net/bzz:/swarm)
|
|
||||||
* [x] adapt to felix's rpc-client-as-eth-backend scheme to run swarm as a separate daemon
|
|
||||||
* [x] merge into main repo develop branch
|
|
||||||
|
|
||||||
## POC 0.3
|
|
||||||
|
|
||||||
Priorities are not finalised, this is just a tentative plan.
|
|
||||||
The following features are prioritised for POC 3 (subject to change)
|
|
||||||
|
|
||||||
* [ ] docker on azure: complete test cluster deployment and remote node control framework
|
|
||||||
* [ ] comprehensive suite of typical network scenarios
|
|
||||||
* [ ] syncer rewrite - syncdb refactor to storage
|
|
||||||
* [ ] mist integration
|
|
||||||
* [ ] storage monitoring and parameter setting API for Mist swarm dashboard
|
|
||||||
* [ ] bzz protocol should implement info for reporting - feature [#2042](https://github.com/ethereum/go-ethereum/issues/2042)
|
|
||||||
* [x] improved peer propagation [#2044](https://github.com/ethereum/go-ethereum/issues/2044)
|
|
||||||
* [x] abstract network simulation framework
|
|
||||||
* [x] protocol stack abstraction, pluggable subprotocol components - (swap, hive/protocol, syncer, peers) for pss
|
|
||||||
* [ ] new p2p API integration - feature [#2060](https://github.com/ethereum/go-ethereum/issues/2060)
|
|
||||||
* [ ] pss - unicast
|
|
||||||
* [ ] swap rewrite
|
|
||||||
* [ ] obfuscation for plausible deniability
|
|
||||||
|
|
||||||
## POC 0.4
|
|
||||||
|
|
||||||
* [ ] enhanced network monitoring, structured logging and stats aggregation
|
|
||||||
* [ ] unicast/multicast messaging over swarm - pss
|
|
||||||
* [ ] swear and swindle http://swarm-gateways.net/bzz:/swarm/ethersphere/orange-papers/1/sw%5E3.pdf
|
|
||||||
* [ ] smash/crash proof of custody http://swarm-gateways.net/bzz:/swarm/ethersphere/orange-papers/2/smash.pdf
|
|
||||||
* [ ] swarm DB support phase 0 - compact manifest trie and proof requests
|
|
||||||
* [ ] [SWarm On-demand Retrieval Daemon](https://gist.github.com/zelig/aa6eb43615e12d834d9f) - feature [#2049](https://github.com/ethereum/go-ethereum/issues/2049) = sword. ethereum state, contract storage, receipts, blocks on swarm
|
|
||||||
* [x] ~implement (a reviewed version of) [EIP-26](https://github.com/ethereum/EIPs/issues/26)~ obsoleted by ENS and the vickrey auction
|
|
||||||
* [ ] swarm namereg/natspec rewrite - enhancement [#2048](https://github.com/ethereum/go-ethereum/issues/2048)
|
|
||||||
* [x] ~solidity [contractInfo standard](https://github.com/ethereum/solidity/pull/645) and contract source verification support~ https://www.reddit.com/r/ethereum/comments/5d5lyd/first_contract_to_contain_swarm_hash_to_its/
|
|
||||||
|
|
||||||
## POC 0.5
|
|
|
@ -1 +0,0 @@
|
||||||
See [Swarm Roadmap](https://github.com/orgs/ethersphere/projects/5)
|
|
|
@ -1 +0,0 @@
|
||||||
See [Swarm Roadmap](https://github.com/orgs/ethersphere/projects/5)
|
|
|
@ -1,935 +0,0 @@
|
||||||
---
|
|
||||||
title: Contract tutorial
|
|
||||||
---
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Now that you mastered the basics on how to get started and how to send ether, it's time to get your hands dirty in what really makes ethereum stand out of the crowd: smart contracts. Smart contracts are pieces of code that live on the blockchain and execute commands exactly how they were told to. They can read other contracts, make decisions, send ether and execute other contracts. Contracts will exist and run as long as the whole network exists, and will only stop if they run out of gas or if they were programmed to self destruct.
|
|
||||||
|
|
||||||
What can you do with contracts? You can do almost anything really, but for this guide let's do some simple things: You will get funds through a crowdfunding that, if successful, will supply a radically transparent and democratic organization that will only obey its own citizens, will never swerve away from its constitution and cannot be censored or shut down. And all that in less than 300 lines of code.
|
|
||||||
|
|
||||||
So let's start now.
|
|
||||||
|
|
||||||
|
|
||||||
## Your first citizen: the greeter
|
|
||||||
|
|
||||||
Now that you’ve mastered the basics of Ethereum, let’s move into your first serious contract. The Frontier is a big open territory and sometimes you might feel lonely, so our first order of business will be to create a little automatic companion to greet you whenever you feel lonely. We’ll call him the “Greeter”.
|
|
||||||
|
|
||||||
The Greeter is an intelligent digital entity that lives on the blockchain and is able to have conversations with anyone who interacts with it, based on its input. It might not be a talker, but it’s a great listener. Here is its code:
|
|
||||||
|
|
||||||
```js
|
|
||||||
contract mortal {
|
|
||||||
/* Define variable owner of the type address*/
|
|
||||||
address owner;
|
|
||||||
|
|
||||||
/* this function is executed at initialization and sets the owner of the contract */
|
|
||||||
function mortal() { owner = msg.sender; }
|
|
||||||
|
|
||||||
/* Function to recover the funds on the contract */
|
|
||||||
function kill() { if (msg.sender == owner) suicide(owner); }
|
|
||||||
}
|
|
||||||
|
|
||||||
contract greeter is mortal {
|
|
||||||
/* define variable greeting of the type string */
|
|
||||||
string greeting;
|
|
||||||
|
|
||||||
/* this runs when the contract is executed */
|
|
||||||
function greeter(string _greeting) public {
|
|
||||||
greeting = _greeting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* main function */
|
|
||||||
function greet() constant returns (string) {
|
|
||||||
return greeting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll notice that there are two different contracts in this code: _"mortal"_ and _"greeter"_. This is because Solidity (the high level contract language we are using) has *inheritance*, meaning that one contract can inherit characteristics of another. This is very useful to simplify coding as common traits of contracts don't need to be rewritten every time, and all contracts can be written in smaller, more readable chunks. So by just declaring that _greeter is mortal_ you inherited all characteristics from the "mortal" contract and kept the greeter code simple and easy to read.
|
|
||||||
|
|
||||||
The inherited characteristic _"mortal"_ simply means that the greeter contract can be killed by its owner, to clean up the blockchain and recover funds locked into it when the contract is no longer needed. Contracts in ethereum are, by default, immortal and have no owner, meaning that once deployed the author has no special privileges anymore. Consider this before deploying.
|
|
||||||
|
|
||||||
### Installing a compiler
|
|
||||||
|
|
||||||
Before you are able to Deploy it though, you'll need two things: the compiled code, and the Application Binary Interface, which is a sort of reference template that defines how to interact with the contract.
|
|
||||||
|
|
||||||
The first you can get by using a compiler. You should have a solidity compiler built in on your geth console. To test it, use this command:
|
|
||||||
|
|
||||||
eth.getCompilers()
|
|
||||||
|
|
||||||
If you have it installed, it should output something like this:
|
|
||||||
|
|
||||||
['Solidity' ]
|
|
||||||
|
|
||||||
If instead the command returns an error, then you need to install it.
|
|
||||||
|
|
||||||
#### Using an online compiler
|
|
||||||
|
|
||||||
If you don't have solC installed, we have a [online solidity compiler](https://chriseth.github.io/cpp-ethereum/) available. But be aware that **if the compiler is compromised, your contract is not safe**. For this reason, if you want to use the online compiler we encourage you to [host your own](https://github.com/chriseth/browser-solidity).
|
|
||||||
|
|
||||||
#### Install SolC on Ubuntu
|
|
||||||
|
|
||||||
Press control+c to exit the console (or type _exit_) and go back to the command line. Open the terminal and execute these commands:
|
|
||||||
|
|
||||||
sudo add-apt-repository ppa:ethereum/ethereum
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install solc
|
|
||||||
which solc
|
|
||||||
|
|
||||||
Take note of the path given by the last line, you'll need it soon.
|
|
||||||
|
|
||||||
#### Install SolC on Mac OSX
|
|
||||||
|
|
||||||
You need [brew](http://brew.sh) in order to install on your mac
|
|
||||||
|
|
||||||
brew tap ethereum/ethereum
|
|
||||||
brew install solidity
|
|
||||||
which solc
|
|
||||||
|
|
||||||
Take note of the path given by the last line, you'll need it soon.
|
|
||||||
|
|
||||||
#### Install SolC on Windows
|
|
||||||
|
|
||||||
You need [chocolatey](http://chocolatey.org) in order to install solc.
|
|
||||||
|
|
||||||
cinst -pre solC-stable
|
|
||||||
|
|
||||||
Windows is more complicated than that, you'll need to wait a bit more.
|
|
||||||
|
|
||||||
If you have the SolC Solidity Compiler installed, you need now reformat by removing spaces so it fits into a string variable [(there are some online tools that will do this)](http://www.textfixer.com/tools/remove-line-breaks.php):
|
|
||||||
|
|
||||||
#### Compile from source
|
|
||||||
|
|
||||||
git clone https://github.com/ethereum/cpp-ethereum.git
|
|
||||||
mkdir cpp-ethereum/build
|
|
||||||
cd cpp-ethereum/build
|
|
||||||
cmake -DJSONRPC=OFF -DMINER=OFF -DETHKEY=OFF -DSERPENT=OFF -DGUI=OFF -DTESTS=OFF -DJSCONSOLE=OFF ..
|
|
||||||
make -j4
|
|
||||||
make install
|
|
||||||
which solc
|
|
||||||
|
|
||||||
#### Linking your compiler in Geth
|
|
||||||
|
|
||||||
Now [go back to the console](../doc/geth) and type this command to install solC, replacing _path/to/solc_ to the path that you got on the last command you did:
|
|
||||||
|
|
||||||
admin.setSolc("path/to/solc")
|
|
||||||
|
|
||||||
Now type again:
|
|
||||||
|
|
||||||
eth.getCompilers()
|
|
||||||
|
|
||||||
If you now have solC installed, then congratulations, you can keep reading. If you don't, then go to our [forums](http://forum.ethereum.org) or [subreddit](http://www.reddit.com/r/ethereum) and berate us on failing to make the process easier.
|
|
||||||
|
|
||||||
|
|
||||||
### Compiling your contract
|
|
||||||
|
|
||||||
|
|
||||||
If you have the compiler installed, you need now reformat your contract by removing line-breaks so it fits into a string variable [(there are some online tools that will do this)](http://www.textfixer.com/tools/remove-line-breaks.php):
|
|
||||||
|
|
||||||
var greeterSource = 'contract mortal { address owner; function mortal() { owner = msg.sender; } function kill() { if (msg.sender == owner) suicide(owner); } } contract greeter is mortal { string greeting; function greeter(string _greeting) public { greeting = _greeting; } function greet() constant returns (string) { return greeting; } }'
|
|
||||||
|
|
||||||
var greeterCompiled = web3.eth.compile.solidity(greeterSource)
|
|
||||||
|
|
||||||
You have now compiled your code. Now you need to get it ready for deployment, this includes setting some variables up, like what is your greeting. Edit the first line below to something more interesting than 'Hello World!" and execute these commands:
|
|
||||||
|
|
||||||
var _greeting = "Hello World!"
|
|
||||||
var greeterContract = web3.eth.contract(greeterCompiled.greeter.info.abiDefinition);
|
|
||||||
|
|
||||||
var greeter = greeterContract.new(_greeting,{from:web3.eth.accounts[0], data: greeterCompiled.greeter.code, gas: 1000000}, function(e, contract){
|
|
||||||
if(!e) {
|
|
||||||
|
|
||||||
if(!contract.address) {
|
|
||||||
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("Contract mined! Address: " + contract.address);
|
|
||||||
console.log(contract);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
#### Using the online compiler
|
|
||||||
|
|
||||||
If you don't have solC installed, you can simply use the online compiler. Copy the source code above to the [online solidity compiler](https://chriseth.github.io/cpp-ethereum/) and then your compiled code should appear on the left pane. Copy the code on the box labeled **Geth deploy** to a text file. Now change the first line to your greeting:
|
|
||||||
|
|
||||||
var _greeting = "Hello World!"
|
|
||||||
|
|
||||||
Now you can paste the resulting text on your geth window. Wait up to thirty seconds and you'll see a message like this:
|
|
||||||
|
|
||||||
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
|
|
||||||
|
|
||||||
You will probably be asked for the password you picked in the beginning, because you need to pay for the gas costs to deploying your contract. This contract is estimated to need 172 thousand gas to deploy (according to the [online solidity compiler](https://chriseth.github.io/cpp-ethereum/)), at the time of writing, gas on the test net is priced at 1 to 10 microethers per unit of gas (nicknamed "szabo" = 1 followed by 12 zeroes in wei). To know the latest price in ether all you can see the [latest gas prices at the network stats page](https://stats.ethdev.com) and multiply both terms.
|
|
||||||
|
|
||||||
**Notice that the cost is not paid to the [ethereum developers](https://ethereum.org), instead it goes to the _Miners_, people who are running computers who keep the network running. Gas price is set by the market of the current supply and demand of computation. If the gas prices are too high, you can be a miner and lower your asking price.**
|
|
||||||
|
|
||||||
|
|
||||||
After less than a minute, you should have a log with the contract address, this means you've sucessfully deployed your contract. You can verify the deployed code (compiled) by using this command:
|
|
||||||
|
|
||||||
eth.getCode(greeter.address)
|
|
||||||
|
|
||||||
If it returns anything other than "0x" then congratulations! Your little Greeter is live! If the contract is created again (by performing another eth.sendTransaction), it will be published to a new address.
|
|
||||||
|
|
||||||
|
|
||||||
### Run the Greeter
|
|
||||||
|
|
||||||
In order to call your bot, just type the following command in your terminal:
|
|
||||||
|
|
||||||
greeter.greet();
|
|
||||||
|
|
||||||
Since this call changes nothing on the blockchain, it returns instantly and without any gas cost. You should see it return your greeting:
|
|
||||||
|
|
||||||
'Hello World!'
|
|
||||||
|
|
||||||
|
|
||||||
### Getting other people to interact with your code
|
|
||||||
|
|
||||||
In order to other people to run your contract they need two things: the address where the contract is located and the ABI (Application Binary Interface) which is a sort of user manual, describing the name of its functions and how to call them. In order to get each of them run these commands:
|
|
||||||
|
|
||||||
greeterCompiled.greeter.info.abiDefinition;
|
|
||||||
greeter.address;
|
|
||||||
|
|
||||||
Then you can instantiate a javascript object which can be used to call the contract on any machine connected to the network. Replace 'ABI' and 'address' to create a contract object in javascript:
|
|
||||||
|
|
||||||
var greeter = eth.contract(ABI).at(Address);
|
|
||||||
|
|
||||||
This particular example can be instantiated by anyone by simply calling:
|
|
||||||
|
|
||||||
var greeter2 = eth.contract([{constant:false,inputs:[],name:'kill',outputs:[],type:'function'},{constant:true,inputs:[],name:'greet',outputs:[{name:'',type:'string'}],type:'function'},{inputs:[{name:'_greeting',type:'string'}],type:'constructor'}]).at('greeterAddress');
|
|
||||||
|
|
||||||
Replace _greeterAddress_ with your contract's address.
|
|
||||||
|
|
||||||
|
|
||||||
**Tip: if the solidity compiler isn't properly installed in your machine, you can get the ABI from the online compiler. To do so, use the code below carefully replacing _greeterCompiled.greeter.info.abiDefinition_ with the abi from your compiler.**
|
|
||||||
|
|
||||||
|
|
||||||
### Cleaning up after yourself:
|
|
||||||
|
|
||||||
You must be very excited to have your first contract live, but this excitement wears off sometimes, when the owners go on to write further contracts, leading to the unpleasant sight of abandoned contracts on the blockchain. In the future, blockchain rent might be implemented in order to increase the scalability of the blockchain but for now, be a good citizen and humanely put down your abandoned bots.
|
|
||||||
|
|
||||||
Unlike last time we will not be making a call as we wish to change something on the blockchain. This requires a transaction be sent to the network and a fee to be paid for the changes made. The suicide is subsidized by the network so it will cost much less than a usual transaction.
|
|
||||||
|
|
||||||
greeter.kill.sendTransaction({from:eth.accounts[0]})
|
|
||||||
|
|
||||||
You can verify that the deed is done simply seeing if this returns 0:
|
|
||||||
|
|
||||||
eth.getCode(greeter.contractAddress)
|
|
||||||
|
|
||||||
Notice that every contract has to implement its own kill clause. In this particular case only the account that created the contract can kill it.
|
|
||||||
|
|
||||||
If you don't add any kill clause it could potentially live forever (or at least until the frontier contracts are all wiped) independently of you and any earthly borders, so before you put it live check what your local laws say about it, including any possible limitation on technology export, restrictions on speech and maybe any legislation on the civil rights of sentient digital beings. Treat your bots humanely.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## The Coin
|
|
||||||
|
|
||||||
What is a coin? Coins are much more interesting and useful than they seem, they are in essence just a tradeable token, but can become much more, depending on how you use them. Its value depends on what you do with it: a token can be used to control access (**an entrance ticket**), can be used for voting rights in an organization (**a share**), can be placeholders for an asset held by a third party (**a certificate of ownership**) or even be simply used as an exchange of value within a community (**a currency**).
|
|
||||||
|
|
||||||
You could do all those things by creating a centralized server, but using an Ethereum token contract comes with some free functionalities: for one, it's a decentralized service and tokens can be still exchanged even if the original service goes down for any reason. The code can guarantee that no tokens will ever be created other than the ones set in the original code. Finally, by having each user hold their own token, this eliminates the scenarios where one single server break-in can result in the loss of funds from thousands of clients.
|
|
||||||
|
|
||||||
You could create your own token on a different blockchain, but creating on ethereum is easier — so you can focus your energy on the innovation that will make your coin stand out - and it's more secure, as your security is provided by all the miners who are supporting the ethereum network. Finally, by creating your token in Ethereum, your coin will be compatible with any other contract running on ethereum.
|
|
||||||
|
|
||||||
### The Code
|
|
||||||
|
|
||||||
This is the code for the contract we're building:
|
|
||||||
|
|
||||||
contract token {
|
|
||||||
mapping (address => uint) public coinBalanceOf;
|
|
||||||
event CoinTransfer(address sender, address receiver, uint amount);
|
|
||||||
|
|
||||||
/* Initializes contract with initial supply tokens to the creator of the contract */
|
|
||||||
function token(uint supply) {
|
|
||||||
coinBalanceOf[msg.sender] = supply;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Very simple trade function */
|
|
||||||
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
|
|
||||||
if (coinBalanceOf[msg.sender] < amount) return false;
|
|
||||||
coinBalanceOf[msg.sender] -= amount;
|
|
||||||
coinBalanceOf[receiver] += amount;
|
|
||||||
CoinTransfer(msg.sender, receiver, amount);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
If you have ever programmed, you won't find it hard to understand what it does: it is a contract that generates 10 thousand tokens to the creator of the contract, and then allows anyone with enough balance to send it to others. These tokens are the minimum tradeable unit and cannot be subdivided, but for the final users could be presented as a 100 units subdividable by 100 subunits, so owning a single token would represent having 0.01% of the total. If your application needs more fine grained atomic divisibility, then just increase the initial issuance amount.
|
|
||||||
|
|
||||||
In this example we declared the variable "coinBalanceOf" to be public, this will automatically create a function that checks any account's balance.
|
|
||||||
|
|
||||||
### Compile and Deploy
|
|
||||||
|
|
||||||
**So let's run it!**
|
|
||||||
|
|
||||||
var tokenSource = ' contract token { mapping (address => uint) public coinBalanceOf; event CoinTransfer(address sender, address receiver, uint amount); /* Initializes contract with initial supply tokens to the creator of the contract */ function token(uint supply) { coinBalanceOf[msg.sender] = supply; } /* Very simple trade function */ function sendCoin(address receiver, uint amount) returns(bool sufficient) { if (coinBalanceOf[msg.sender] < amount) return false; coinBalanceOf[msg.sender] -= amount; coinBalanceOf[receiver] += amount; CoinTransfer(msg.sender, receiver, amount); return true; } }'
|
|
||||||
|
|
||||||
var tokenCompiled = eth.compile.solidity(tokenSource)
|
|
||||||
|
|
||||||
Now let’s set up the contract, just like we did in the previous section. Change the "initial Supply" to the amount of non divisible tokens you want to create. If you want to have divisible units, you should do that on the user frontend but keep them represented in the minimun unit of account.
|
|
||||||
|
|
||||||
var supply = 10000;
|
|
||||||
var tokenContract = web3.eth.contract(tokenCompiled.token.info.abiDefinition);
|
|
||||||
var token = tokenContract.new(
|
|
||||||
supply,
|
|
||||||
{
|
|
||||||
from:web3.eth.accounts[0],
|
|
||||||
data:tokenCompiled.token.code,
|
|
||||||
gas: 1000000
|
|
||||||
}, function(e, contract){
|
|
||||||
if(!e) {
|
|
||||||
|
|
||||||
if(!contract.address) {
|
|
||||||
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("Contract mined! Address: " + contract.address);
|
|
||||||
console.log(contract);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
#### Online Compiler
|
|
||||||
|
|
||||||
**If you don't have solC installed, you can simply use the online compiler.** Copy the contract code to the [online solidity compiler](https://chriseth.github.io/cpp-ethereum/), if there are no errors on the contract you should see a text box labeled **Geth Deploy**. Copy the content to a text file so you can change the first line to set the initial supply, like this:
|
|
||||||
|
|
||||||
var supply = 10000;
|
|
||||||
|
|
||||||
Now you can paste the resulting text on your geth window. Wait up to thirty seconds and you'll see a message like this:
|
|
||||||
|
|
||||||
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
|
|
||||||
|
|
||||||
|
|
||||||
### Check balance watching coin transfers
|
|
||||||
|
|
||||||
If everything worked correctly, you should be able to check your own balance with:
|
|
||||||
|
|
||||||
token.coinBalanceOf(eth.accounts[0]) + " tokens"
|
|
||||||
|
|
||||||
It should have all the 10 000 tokens that were created once the contract was published. Since there is not any other defined way for new coins to be issued, these are all that will ever exist.
|
|
||||||
|
|
||||||
You can set up a **Watcher** to react whenever anyone sends a coin using your contract. Here's how you do it:
|
|
||||||
|
|
||||||
var event = token.CoinTransfer({}, '', function(error, result){
|
|
||||||
if (!error)
|
|
||||||
console.log("Coin transfer: " + result.args.amount + " tokens were sent. Balances now are as following: \n Sender:\t" + result.args.sender + " \t" + token.coinBalanceOf.call(result.args.sender) + " tokens \n Receiver:\t" + result.args.receiver + " \t" + token.coinBalanceOf.call(result.args.receiver) + " tokens" )
|
|
||||||
});
|
|
||||||
|
|
||||||
### Sending coins
|
|
||||||
|
|
||||||
Now of course those tokens aren't very useful if you hoard them all, so in order to send them to someone else, use this command:
|
|
||||||
|
|
||||||
token.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]})
|
|
||||||
|
|
||||||
If a friend has registered a name on the registrar you can send it without knowing their address, doing this:
|
|
||||||
|
|
||||||
token.sendCoin.sendTransaction(registrar.addr("Alice"), 2000, {from: eth.accounts[0]})
|
|
||||||
|
|
||||||
|
|
||||||
Note that our first function **coinBalanceOf** was simply called directly on the contract instance and returned a value. This was possible since this was a simple read operation that incurs no state change and which executes locally and synchronously. Our second function **sendCoin** needs a **.sendTransaction()** call. Since this function is meant to change the state (write operation), it is sent as a transaction to the network to be picked up by miners and included in the canonical blockchain. As a result the consensus state of all participant nodes will adequately reflect the state changes resulting from executing the transaction. Sender address needs to be sent as part of the transaction to fund the fuel needed to run the transaction. Now, wait a minute and check both accounts balances:
|
|
||||||
|
|
||||||
token.coinBalanceOf.call(eth.accounts[0])/100 + "% of all tokens"
|
|
||||||
token.coinBalanceOf.call(eth.accounts[1])/100 + "% of all tokens"
|
|
||||||
token.coinBalanceOf.call(registrar.addr("Alice"))/100 + "% of all tokens"
|
|
||||||
|
|
||||||
|
|
||||||
### Improvement suggestions
|
|
||||||
|
|
||||||
Right now this cryptocurrency is quite limited as there will only ever be 10,000 coins and all are controlled by the coin creator, but you can change that. You could for example reward ethereum miners, by creating a transaction that will reward who found the current block:
|
|
||||||
|
|
||||||
mapping (uint => address) miningReward;
|
|
||||||
function claimMiningReward() {
|
|
||||||
if (miningReward[block.number] == 0) {
|
|
||||||
coinBalanceOf[block.coinbase] += 1;
|
|
||||||
miningReward[block.number] = block.coinbase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
You could modify this to anything else: maybe reward someone who finds a solution for a new puzzle, wins a game of chess, install a solar panel—as long as that can be somehow translated to a contract. Or maybe you want to create a central bank for your personal country, so you can keep track of hours worked, favours owed or control of property. In that case you might want to add a function to allow the bank to remotely freeze funds and destroy tokens if needed.
|
|
||||||
|
|
||||||
|
|
||||||
### Register a name for your coin
|
|
||||||
|
|
||||||
The commands mentioned only work because you have token javascript object instantiated on your local machine. If you send tokens to someone they won't be able to move them forward because they don't have the same object and wont know where to look for your contract or call its functions. In fact if you restart your console these objects will be deleted and the contracts you've been working on will be lost forever. So how do you instantiate the contract on a clean machine?
|
|
||||||
|
|
||||||
There are two ways. Let's start with the quick and dirty, providing your friends with a reference to your contract’s ABI:
|
|
||||||
|
|
||||||
token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at('0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8')
|
|
||||||
|
|
||||||
Just replace the address at the end for your own token address, then anyone that uses this snippet will immediately be able to use your contract. Of course this will work only for this specific contract so let's analyze step by step and see how to improve this code so you'll be able to use it anywhere.
|
|
||||||
|
|
||||||
All accounts are referenced in the network by their public address. But addresses are long, difficult to write down, hard to memorize and immutable. The last one is specially important if you want to be able to generate fresh accounts in your name, or upgrade the code of your contract. In order to solve this, there is a default name registrar contract which is used to associate the long addresses with short, human-friendly names.
|
|
||||||
|
|
||||||
Names have to use only alphanumeric characters and, cannot contain blank spaces. In future releases the name registrar will likely implement a bidding process to prevent name squatting but for now, it works on a first come first served basis: as long as no one else registered the name, you can claim it.
|
|
||||||
|
|
||||||
|
|
||||||
First, if you register a name, then you won't need the hardcoded address in the end. Select a nice coin name and try to reserve it for yourself. First, select your name:
|
|
||||||
|
|
||||||
var tokenName = "MyFirstCoin"
|
|
||||||
|
|
||||||
Then, check the availability of your name:
|
|
||||||
|
|
||||||
registrar.addr(tokenName)
|
|
||||||
|
|
||||||
If that function returns "0x00..", you can claim it to yourself:
|
|
||||||
|
|
||||||
registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]});
|
|
||||||
|
|
||||||
|
|
||||||
Wait for the previous transaction to be picked up. Wait up to thirty seconds and then try:
|
|
||||||
|
|
||||||
registrar.owner(myName)
|
|
||||||
|
|
||||||
If it returns your address, it means you own that name and are able to set your chosen name to any address you want:
|
|
||||||
|
|
||||||
registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]});
|
|
||||||
|
|
||||||
_You can replace **token.address** for **eth.accounts[0]** if you want to use it as a personal nickname._
|
|
||||||
|
|
||||||
Wait a little bit for that transaction to be picked up too and test it:
|
|
||||||
|
|
||||||
registrar.addr("MyFirstCoin")
|
|
||||||
|
|
||||||
You can send a transaction to anyone or any contract by name instead of account simply by typing
|
|
||||||
|
|
||||||
eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")})
|
|
||||||
|
|
||||||
**Tip: don't mix registrar.addr for registrar.owner. The first is to which address that name is pointed at: anyone can point a name to anywhere else, just like anyone can forward a link to google.com, but only the owner of the name can change and update the link. You can set both to be the same address.**
|
|
||||||
|
|
||||||
This should now return your token address, meaning that now the previous code to instantiate could use a name instead of an address.
|
|
||||||
|
|
||||||
token = eth.contract([{constant:false,inputs:[{name:'receiver',type:'address'},{name:'amount',type:'uint256'}],name:'sendCoin',outputs:[{name:'sufficient',type:'bool'}],type:'function'},{constant:true,inputs:[{name:'',type:'address'}],name:'coinBalanceOf',outputs:[{name:'',type:'uint256'}],type:'function'},{inputs:[{name:'supply',type:'uint256'}],type:'constructor'},{anonymous:false,inputs:[{indexed:false,name:'sender',type:'address'},{indexed:false,name:'receiver',type:'address'},{indexed:false,name:'amount',type:'uint256'}],name:'CoinTransfer',type:'event'}]).at(registrar.addr("MyFirstCoin"))
|
|
||||||
|
|
||||||
This also means that the owner of the coin can update the coin by pointing the registrar to the new contract. This would, of course, require the coin holders trust the owner set at registrar.owner("MyFirstCoin")
|
|
||||||
|
|
||||||
### Learn More
|
|
||||||
|
|
||||||
* [Meta coin standard](https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs) is a proposed standardization of function names for coin and token contracts, to allow them to be automatically added to other ethereum contract that utilizes trading, like exchanges or escrow.
|
|
||||||
|
|
||||||
* [Formal proofing](https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format#documentation-output) is a way where the contract developer will be able to assert some invariant qualities of the contract, like the total cap of the coin. *Not yet implemented*.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Crowdfund your idea
|
|
||||||
|
|
||||||
Sometimes a good idea takes a lot of funds and collective effort. You could ask for donations, but donors prefer to give to projects they are more certain that will get traction and proper funding. This is an example where a crowdfunding would be ideal: you set up a goal and a deadline for reaching it. If you miss your goal, the donations are returned, therefore reducing the risk for donors. Since the code is open and auditable, there is no need for a centralized trusted platform and therefore the only fees everyone will pay are just the gas fees.
|
|
||||||
|
|
||||||
In a crowdfunding prizes are usually given. This would require you to get everyone's contact information and keep track of who owns what. But since you just created your own token, why not use that to keep track of the prizes? This allows donors to immediately own something after they donated. They can store it safely, but they can also sell or trade it if they realize they don't want the prize anymore. If your idea is something physical, all you have to do after the project is completed is to give the product to everyone who sends you back a token. If the project is digital the token itself can immediately be used for users to participate or get entry on your project.
|
|
||||||
|
|
||||||
### The code
|
|
||||||
|
|
||||||
The way this particular crowdsale contract works is that you set an exchange rate for your token and then the donors will immediately get a proportional amount of tokens in exchange of their ether. You will also choose a funding goal and a deadline: once that deadline is over you can ping the contract and if the goal was reached it will send the ether raised to you, otherwise it goes back to the donors. Donors keep their tokens even if the project doesn't reach its goal, as a proof that they helped.
|
|
||||||
|
|
||||||
|
|
||||||
contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } }
|
|
||||||
|
|
||||||
contract Crowdsale {
|
|
||||||
|
|
||||||
address public beneficiary;
|
|
||||||
uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price;
|
|
||||||
token public tokenReward;
|
|
||||||
Funder[] public funders;
|
|
||||||
event FundTransfer(address backer, uint amount, bool isContribution);
|
|
||||||
|
|
||||||
/* data structure to hold information about campaign contributors */
|
|
||||||
struct Funder {
|
|
||||||
address addr;
|
|
||||||
uint amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* at initialization, setup the owner */
|
|
||||||
function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) {
|
|
||||||
beneficiary = _beneficiary;
|
|
||||||
fundingGoal = _fundingGoal;
|
|
||||||
deadline = now + _duration * 1 minutes;
|
|
||||||
price = _price;
|
|
||||||
tokenReward = token(_reward);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The function without name is the default function that is called whenever anyone sends funds to a contract */
|
|
||||||
function () {
|
|
||||||
uint amount = msg.value;
|
|
||||||
funders[funders.length++] = Funder({addr: msg.sender, amount: amount});
|
|
||||||
amountRaised += amount;
|
|
||||||
tokenReward.sendCoin(msg.sender, amount / price);
|
|
||||||
FundTransfer(msg.sender, amount, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier afterDeadline() { if (now >= deadline) _ }
|
|
||||||
|
|
||||||
/* checks if the goal or time limit has been reached and ends the campaign */
|
|
||||||
function checkGoalReached() afterDeadline {
|
|
||||||
if (amountRaised >= fundingGoal){
|
|
||||||
beneficiary.send(amountRaised);
|
|
||||||
FundTransfer(beneficiary, amountRaised, false);
|
|
||||||
} else {
|
|
||||||
FundTransfer(0, 11, false);
|
|
||||||
for (uint i = 0; i < funders.length; ++i) {
|
|
||||||
funders[i].addr.send(funders[i].amount);
|
|
||||||
FundTransfer(funders[i].addr, funders[i].amount, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suicide(beneficiary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
### Set the parameters
|
|
||||||
|
|
||||||
Before we go further, let's start by setting the parameters of the crowdsale:
|
|
||||||
|
|
||||||
var _beneficiary = eth.accounts[1]; // create an account for this
|
|
||||||
var _fundingGoal = web3.toWei(100, "ether"); // raises 100 ether
|
|
||||||
var _duration = 30; // number of minutes the campaign will last
|
|
||||||
var _price = web3.toWei(0.02, "ether"); // the price of the tokens, in ether
|
|
||||||
var _reward = token.address; // the token contract address.
|
|
||||||
|
|
||||||
On Beneficiary put the new address that will receive the raised funds. The funding goal is the amount of ether to be raised. Deadline is measured in blocktimes which average 12 seconds, so the default is about 4 weeks. The price is tricky: but just change the number 2 for the amount of tokens the contributors will receive for each ether donated. Finally reward should be the address of the token contract you created in the last section.
|
|
||||||
|
|
||||||
In this example you are selling on the crowdsale half of all the tokens that ever existed, in exchange for 100 ether. Decide those parameters very carefully as they will play a very important role in the next part of our guide.
|
|
||||||
|
|
||||||
### Deploy
|
|
||||||
|
|
||||||
You know the drill: if you are using the solC compiler,[remove line breaks](http://www.textfixer.com/tools/remove-line-breaks.php) and copy the following commands on the terminal:
|
|
||||||
|
|
||||||
|
|
||||||
var crowdsaleCompiled = eth.compile.solidity(' contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Crowdsale { address public beneficiary; uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; token public tokenReward; Funder[] public funders; event FundTransfer(address backer, uint amount, bool isContribution); /* data structure to hold information about campaign contributors */ struct Funder { address addr; uint amount; } /* at initialization, setup the owner */ function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) { beneficiary = _beneficiary; fundingGoal = _fundingGoal; deadline = now + _duration * 1 minutes; price = _price; tokenReward = token(_reward); } /* The function without name is the default function that is called whenever anyone sends funds to a contract */ function () { Funder f = funders[++funders.length]; f.addr = msg.sender; f.amount = msg.value; amountRaised += f.amount; tokenReward.sendCoin(msg.sender, f.amount/price); FundTransfer(f.addr, f.amount, true); } modifier afterDeadline() { if (now >= deadline) _ } /* checks if the goal or time limit has been reached and ends the campaign */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal){ beneficiary.send(amountRaised); FundTransfer(beneficiary, amountRaised, false); } else { FundTransfer(0, 11, false); for (uint i = 0; i < funders.length; ++i) { funders[i].addr.send(funders[i].amount); FundTransfer(funders[i].addr, funders[i].amount, false); } } suicide(beneficiary); } }');
|
|
||||||
|
|
||||||
var crowdsaleContract = web3.eth.contract(crowdsaleCompiled.Crowdsale.info.abiDefinition);
|
|
||||||
var crowdsale = crowdsaleContract.new(
|
|
||||||
_beneficiary,
|
|
||||||
_fundingGoal,
|
|
||||||
_duration,
|
|
||||||
_price,
|
|
||||||
_reward,
|
|
||||||
{
|
|
||||||
from:web3.eth.accounts[0],
|
|
||||||
data:crowdsaleCompiled.Crowdsale.code,
|
|
||||||
gas: 1000000
|
|
||||||
}, function(e, contract){
|
|
||||||
if(!e) {
|
|
||||||
|
|
||||||
if(!contract.address) {
|
|
||||||
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("Contract mined! Address: " + contract.address);
|
|
||||||
console.log(contract);
|
|
||||||
}
|
|
||||||
|
|
||||||
} })
|
|
||||||
|
|
||||||
**If you are using the _online compiler_ Copy the contract code to the [online solidity compiler](https://chriseth.github.io/cpp-ethereum/), and then grab the content of the box labeled **Geth Deploy**. Since you have already set the parameters, you don't need to change anything to that text, simply paste the resulting text on your geth window.**
|
|
||||||
|
|
||||||
Wait up to thirty seconds and you'll see a message like this:
|
|
||||||
|
|
||||||
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
|
|
||||||
|
|
||||||
If you received that alert then your code should be online. You can always double check by doing this:
|
|
||||||
|
|
||||||
eth.getCode(crowdsale.address)
|
|
||||||
|
|
||||||
Now fund your newly created contract with the necessary tokens so it can automatically distribute rewards to the contributors!
|
|
||||||
|
|
||||||
token.sendCoin.sendTransaction(crowdsale.address, 5000,{from: eth.accounts[0]})
|
|
||||||
|
|
||||||
After the transaction is picked, you can check the amount of tokens the crowdsale address has, and all other variables this way:
|
|
||||||
|
|
||||||
"Current crowdsale must raise " + web3.fromWei(crowdsale.fundingGoal.call(), "ether") + " ether in order to send it to " + crowdsale.beneficiary.call() + "."
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Put some watchers on
|
|
||||||
|
|
||||||
You want to be alerted whenever your crowdsale receives new funds, so paste this code:
|
|
||||||
|
|
||||||
var event = crowdsale.FundTransfer({}, '', function(error, result){
|
|
||||||
if (!error)
|
|
||||||
|
|
||||||
if (result.args.isContribution) {
|
|
||||||
console.log("\n New backer! Received " + web3.fromWei(result.args.amount, "ether") + " ether from " + result.args.backer )
|
|
||||||
|
|
||||||
console.log( "\n The current funding at " +( 100 * crowdsale.amountRaised.call() / crowdsale.fundingGoal.call()) + "% of its goals. Funders have contributed a total of " + web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether.");
|
|
||||||
|
|
||||||
var timeleft = Math.floor(Date.now() / 1000)-crowdsale.deadline();
|
|
||||||
if (timeleft>3600) { console.log("Deadline has passed, " + Math.floor(timeleft/3600) + " hours ago")
|
|
||||||
} else if (timeleft>0) { console.log("Deadline has passed, " + Math.floor(timeleft/60) + " minutes ago")
|
|
||||||
} else if (timeleft>-3600) { console.log(Math.floor(-1*timeleft/60) + " minutes until deadline")
|
|
||||||
} else { console.log(Math.floor(-1*timeleft/3600) + " hours until deadline")
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("Funds transferred from crowdsale account: " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.backer )
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Register the contract
|
|
||||||
|
|
||||||
You are now set. Anyone can now contribute by simply sending ether to the crowdsale address, but to make it even simpler, let's register a name for your sale. First, pick a name for your crowdsale:
|
|
||||||
|
|
||||||
var name = "mycrowdsale"
|
|
||||||
|
|
||||||
Check if that's available and register:
|
|
||||||
|
|
||||||
registrar.addr(name)
|
|
||||||
registrar.reserve.sendTransaction(name, {from: eth.accounts[0]});
|
|
||||||
|
|
||||||
Wait for the previous transaction to be picked up and then:
|
|
||||||
|
|
||||||
registrar.setAddress.sendTransaction(name, crowdsale.address, true,{from: eth.accounts[0]});
|
|
||||||
|
|
||||||
|
|
||||||
### Contribute to the crowdsale
|
|
||||||
|
|
||||||
Contributing to the crowdsale is very simple, it doesn't even require instantiating the contract. This is because the crowdsale responds to simple ether deposits, so anyone that sends ether to the crowdsale will automatically receive a reward.
|
|
||||||
Anyone can contribute to it by simply executing this command:
|
|
||||||
|
|
||||||
var amount = web3.toWei(5, "ether") // decide how much to contribute
|
|
||||||
|
|
||||||
eth.sendTransaction({from: eth.accounts[0], to: crowdsale.address, value: amount, gas: 1000000})
|
|
||||||
|
|
||||||
|
|
||||||
Alternatively, if you want someone else to send it, they can even use the name registrar to contribute:
|
|
||||||
|
|
||||||
eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("mycrowdsale"), value: amount, gas: 500000})
|
|
||||||
|
|
||||||
|
|
||||||
Now wait a minute for the blocks to pickup and you can check if the contract received the ether by doing any of these commands:
|
|
||||||
|
|
||||||
web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether"
|
|
||||||
token.coinBalanceOf.call(eth.accounts[0]) + " tokens"
|
|
||||||
token.coinBalanceOf.call(crowdsale.address) + " tokens"
|
|
||||||
|
|
||||||
|
|
||||||
### Recover funds
|
|
||||||
|
|
||||||
Once the deadline is passed someone has to wake up the contract to have the funds sent to either the beneficiary or back to the funders (if it failed). This happens because there is no such thing as an active loop or timer on ethereum so any future transactions must be pinged by someone.
|
|
||||||
|
|
||||||
crowdsale.checkGoalReached.sendTransaction({from:eth.accounts[0], gas: 2000000})
|
|
||||||
|
|
||||||
You can check your accounts with these lines of code:
|
|
||||||
|
|
||||||
web3.fromWei(eth.getBalance(eth.accounts[0]), "ether") + " ether"
|
|
||||||
web3.fromWei(eth.getBalance(eth.accounts[1]), "ether") + " ether"
|
|
||||||
token.coinBalanceOf.call(eth.accounts[0]) + " tokens"
|
|
||||||
token.coinBalanceOf.call(eth.accounts[1]) + " tokens"
|
|
||||||
|
|
||||||
The crowdsale instance is setup to self destruct once it has done its job, so if the deadline is over and everyone got their prizes the contract is no more, as you can see by running this:
|
|
||||||
|
|
||||||
eth.getCode(crowdsale.address)
|
|
||||||
|
|
||||||
So you raised a 100 ethers and successfully distributed your original coin among the crowdsale donors. What could you do next with those things?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Democracy DAO
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
So far you have created a tradeable token and you successfully distributed it among all those who were willing to help fundraise a 100 ethers. That's all very interesting but what exactly are those tokens for? Why would anyone want to own or trade it for anything else valuable? If you can convince your new token is the next big money maybe others will want it, but so far your token offers no value per se. We are going to change that, by creating your first decentralized autonomous organization, or DAO.
|
|
||||||
|
|
||||||
Think of the DAO as the constitution of a country, the executive branch of a government or maybe like a robotic manager for an organization. The DAO receives the money that your organization raises, keeps it safe and uses it to fund whatever its members want. The robot is incorruptible, will never defraud the bank, never create secret plans, never use the money for anything other than what its constituents voted on. The DAO will never disappear, never run away and cannot be controlled by anyone other than its own citizens.
|
|
||||||
|
|
||||||
The token we distributed using the crowdsale is the only citizen document needed. Anyone who holds any token is able to create and vote on proposals. Similar to being a shareholder in a company, the token can be traded on the open market and the vote is proportional to amounts of tokens the voter holds.
|
|
||||||
|
|
||||||
Take a moment to dream about the revolutionary possibilities this would allow, and now you can do it yourself, in under a 100 lines of code:
|
|
||||||
|
|
||||||
|
|
||||||
### The Code
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } }
|
|
||||||
|
|
||||||
|
|
||||||
contract Democracy {
|
|
||||||
|
|
||||||
uint public minimumQuorum;
|
|
||||||
uint public debatingPeriod;
|
|
||||||
token public voterShare;
|
|
||||||
address public founder;
|
|
||||||
Proposal[] public proposals;
|
|
||||||
uint public numProposals;
|
|
||||||
|
|
||||||
event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description);
|
|
||||||
event Voted(uint proposalID, int position, address voter);
|
|
||||||
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
|
|
||||||
|
|
||||||
struct Proposal {
|
|
||||||
address recipient;
|
|
||||||
uint amount;
|
|
||||||
bytes32 data;
|
|
||||||
string description;
|
|
||||||
uint creationDate;
|
|
||||||
bool active;
|
|
||||||
Vote[] votes;
|
|
||||||
mapping (address => bool) voted;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Vote {
|
|
||||||
int position;
|
|
||||||
address voter;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) {
|
|
||||||
founder = msg.sender;
|
|
||||||
voterShare = token(_voterShareAddress);
|
|
||||||
minimumQuorum = _minimumQuorum || 10;
|
|
||||||
debatingPeriod = _debatingPeriod * 1 minutes || 30 days;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) {
|
|
||||||
if (voterShare.coinBalanceOf(msg.sender)>0) {
|
|
||||||
proposalID = proposals.length++;
|
|
||||||
Proposal p = proposals[proposalID];
|
|
||||||
p.recipient = _recipient;
|
|
||||||
p.amount = _amount;
|
|
||||||
p.data = _data;
|
|
||||||
p.description = _description;
|
|
||||||
p.creationDate = now;
|
|
||||||
p.active = true;
|
|
||||||
ProposalAdded(proposalID, _recipient, _amount, _data, _description);
|
|
||||||
numProposals = proposalID+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function vote(uint _proposalID, int _position) returns (uint voteID){
|
|
||||||
if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) {
|
|
||||||
Proposal p = proposals[_proposalID];
|
|
||||||
if (p.voted[msg.sender] == true) return;
|
|
||||||
voteID = p.votes.length++;
|
|
||||||
p.votes[voteID] = Vote({position: _position, voter: msg.sender});
|
|
||||||
p.voted[msg.sender] = true;
|
|
||||||
Voted(_proposalID, _position, msg.sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeProposal(uint _proposalID) returns (int result) {
|
|
||||||
Proposal p = proposals[_proposalID];
|
|
||||||
/* Check if debating period is over */
|
|
||||||
if (now > (p.creationDate + debatingPeriod) && p.active){
|
|
||||||
uint quorum = 0;
|
|
||||||
/* tally the votes */
|
|
||||||
for (uint i = 0; i < p.votes.length; ++i) {
|
|
||||||
Vote v = p.votes[i];
|
|
||||||
uint voteWeight = voterShare.coinBalanceOf(v.voter);
|
|
||||||
quorum += voteWeight;
|
|
||||||
result += int(voteWeight) * v.position;
|
|
||||||
}
|
|
||||||
/* execute result */
|
|
||||||
if (quorum > minimumQuorum && result > 0 ) {
|
|
||||||
p.recipient.call.value(p.amount)(p.data);
|
|
||||||
p.active = false;
|
|
||||||
} else if (quorum > minimumQuorum && result < 0) {
|
|
||||||
p.active = false;
|
|
||||||
}
|
|
||||||
ProposalTallied(_proposalID, result, quorum, p.active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
There's a lot of going on but it's simpler than it looks. The rules of your organization are very simple: anyone with at least one token can create proposals to send funds from the country's account. After a week of debate and votes, if it has received votes worth a total of 100 tokens or more and has more approvals than rejections, the funds will be sent. If the quorum hasn't been met or it ends on a tie, then voting is kept until it's resolved. Otherwise, the proposal is locked and kept for historical purposes.
|
|
||||||
|
|
||||||
So let's recap what this means: in the last two sections you created 10,000 tokens, sent 1,000 of those to another account you control, 2,000 to a friend named Alice and distributed 5,000 of them via a crowdsale. This means that you no longer control over 50% of the votes in the DAO, and if Alice and the community bands together, they can outvote any spending decision on the 100 ethers raised so far. This is exactly how a democracy should work. If you don't want to be a part of your country anymore the only thing you can do is sell your own tokens on a decentralized exchange and opt out, but you cannot prevent the others from doing so.
|
|
||||||
|
|
||||||
|
|
||||||
### Set Up your Organization
|
|
||||||
|
|
||||||
So open your console and let's get ready to finally put your country online. First, let's set the right parameters, pick them with care:
|
|
||||||
|
|
||||||
var _voterShareAddress = token.address;
|
|
||||||
var _minimumQuorum = 10; // Minimun amount of voter tokens the proposal needs to pass
|
|
||||||
var _debatingPeriod = 60; // debating period, in minutes;
|
|
||||||
|
|
||||||
With these default parameters anyone with any tokens can make a proposal on how to spend the organization's money. The proposal has 1 hour to be debated and it will pass if it has at least votes from at least 0.1% of the total tokens and has more support than rejections. Pick those parameters with care, as you won't be able to change them in the future.
|
|
||||||
|
|
||||||
var daoCompiled = eth.compile.solidity('contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Democracy { uint public minimumQuorum; uint public debatingPeriod; token public voterShare; address public founder; Proposal[] public proposals; uint public numProposals; event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description); event Voted(uint proposalID, int position, address voter); event ProposalTallied(uint proposalID, int result, uint quorum, bool active); struct Proposal { address recipient; uint amount; bytes32 data; string description; uint creationDate; bool active; Vote[] votes; mapping (address => bool) voted; } struct Vote { int position; address voter; } function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) { founder = msg.sender; voterShare = token(_voterShareAddress); minimumQuorum = _minimumQuorum || 10; debatingPeriod = _debatingPeriod * 1 minutes || 30 days; } function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) { if (voterShare.coinBalanceOf(msg.sender)>0) { proposalID = proposals.length++; Proposal p = proposals[proposalID]; p.recipient = _recipient; p.amount = _amount; p.data = _data; p.description = _description; p.creationDate = now; p.active = true; ProposalAdded(proposalID, _recipient, _amount, _data, _description); numProposals = proposalID+1; } else { return 0; } } function vote(uint _proposalID, int _position) returns (uint voteID){ if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) { Proposal p = proposals[_proposalID]; if (p.voted[msg.sender] == true) return; voteID = p.votes.length++; Vote v = p.votes[voteID]; v.position = _position; v.voter = msg.sender; p.voted[msg.sender] = true; Voted(_proposalID, _position, msg.sender); } else { return 0; } } function executeProposal(uint _proposalID) returns (int result) { Proposal p = proposals[_proposalID]; /* Check if debating period is over */ if (now > (p.creationDate + debatingPeriod) && p.active){ uint quorum = 0; /* tally the votes */ for (uint i = 0; i < p.votes.length; ++i) { Vote v = p.votes[i]; uint voteWeight = voterShare.coinBalanceOf(v.voter); quorum += voteWeight; result += int(voteWeight) * v.position; } /* execute result */ if (quorum > minimumQuorum && result > 0 ) { p.recipient.call.value(p.amount)(p.data); p.active = false; } else if (quorum > minimumQuorum && result < 0) { p.active = false; } } ProposalTallied(_proposalID, result, quorum, p.active); } }');
|
|
||||||
|
|
||||||
var democracyContract = web3.eth.contract(daoCompiled.Democracy.info.abiDefinition);
|
|
||||||
|
|
||||||
var democracy = democracyContract.new(
|
|
||||||
_voterShareAddress,
|
|
||||||
_minimumQuorum,
|
|
||||||
_debatingPeriod,
|
|
||||||
{
|
|
||||||
from:web3.eth.accounts[0],
|
|
||||||
data:daoCompiled.Democracy.code,
|
|
||||||
gas: 3000000
|
|
||||||
}, function(e, contract){
|
|
||||||
if(!e) {
|
|
||||||
|
|
||||||
if(!contract.address) {
|
|
||||||
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("Contract mined! Address: " + contract.address);
|
|
||||||
console.log(contract);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
**If you are using the _online compiler_ Copy the contract code to the [online solidity compiler](https://chriseth.github.io/cpp-ethereum/), and then grab the content of the box labeled **Geth Deploy**. Since you have already set the parameters, you don't need to change anything to that text, simply paste the resulting text on your geth window.**
|
|
||||||
|
|
||||||
Wait a minute until the miners pick it up. It will cost you about 850k Gas. Once that is picked up, it's time to instantiate it and set it up, by pointing it to the correct address of the token contract you created previously.
|
|
||||||
|
|
||||||
If everything worked out, you can take a look at the whole organization by executing this string:
|
|
||||||
|
|
||||||
"This organization has " + democracy.numProposals() + " proposals and uses the token at the address " + democracy.voterShare() ;
|
|
||||||
|
|
||||||
If everything is setup then your DAO should return a proposal count of 0 and an address marked as the "founder". While there are still no proposals, the founder of the DAO can change the address of the token to anything it wants.
|
|
||||||
|
|
||||||
### Register your organization name
|
|
||||||
|
|
||||||
Let's also register a name for your contract so it's easily accessible (don't forget to check your name availability with registrar.addr("nameYouWant") before reserving!)
|
|
||||||
|
|
||||||
var name = "MyPersonalDemocracy"
|
|
||||||
registrar.reserve.sendTransaction(name, {from: eth.accounts[0]})
|
|
||||||
var democracy = eth.contract(daoCompiled.Democracy.info.abiDefinition).at(democracy.address);
|
|
||||||
democracy.setup.sendTransaction(registrar.addr("MyFirstCoin"),{from:eth.accounts[0]})
|
|
||||||
|
|
||||||
Wait for the previous transactions to be picked up and then:
|
|
||||||
|
|
||||||
registrar.setAddress.sendTransaction(name, democracy.address, true,{from: eth.accounts[0]});
|
|
||||||
|
|
||||||
|
|
||||||
### The Democracy Watchbots
|
|
||||||
|
|
||||||
|
|
||||||
var event = democracy.ProposalAdded({}, '', function(error, result){
|
|
||||||
if (!error)
|
|
||||||
console.log("New Proposal #"+ result.args.proposalID +"!\n Send " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.recipient.substring(2,8) + "... for " + result.args.description )
|
|
||||||
});
|
|
||||||
var eventVote = democracy.Voted({}, '', function(error, result){
|
|
||||||
if (!error)
|
|
||||||
var opinion = "";
|
|
||||||
if (result.args.position > 0) {
|
|
||||||
opinion = "in favor"
|
|
||||||
} else if (result.args.position < 0) {
|
|
||||||
opinion = "against"
|
|
||||||
} else {
|
|
||||||
opinion = "abstaining"
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Vote on Proposal #"+ result.args.proposalID +"!\n " + result.args.voter + " is " + opinion )
|
|
||||||
});
|
|
||||||
var eventTally = democracy.ProposalTallied({}, '', function(error, result){
|
|
||||||
if (!error)
|
|
||||||
var totalCount = "";
|
|
||||||
if (result.args.result > 1) {
|
|
||||||
totalCount = "passed"
|
|
||||||
} else if (result.args.result < 1) {
|
|
||||||
totalCount = "rejected"
|
|
||||||
} else {
|
|
||||||
totalCount = "a tie"
|
|
||||||
}
|
|
||||||
console.log("Votes counted on Proposal #"+ result.args.proposalID +"!\n With a total of " + Math.abs(result.args.result) + " out of " + result.args.quorum + ", proposal is " + totalCount + ". Proposal is " + (result.args.active? " still on the floor" : "archived") )
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
### Interacting with the DAO
|
|
||||||
|
|
||||||
After you are satisfied with what you want, it's time to get all that ether you got from the crowdfunding into your new organization:
|
|
||||||
|
|
||||||
eth.sendTransaction({from: eth.accounts[1], to: democracy.address, value: web3.toWei(100, "ether")})
|
|
||||||
|
|
||||||
This should take only a minute and your country is ready for business! Now, as a first priority, your organisation needs a nice logo, but unless you are a designer, you have no idea how to do that. For the sake of argument let's say you find that your friend Bob is a great designer who's willing to do it for only 10 ethers, so you want to propose to hire him.
|
|
||||||
|
|
||||||
recipient = registrar.addr("bob");
|
|
||||||
amount = web3.toWei(10, "ether");
|
|
||||||
shortNote = "Logo Design";
|
|
||||||
|
|
||||||
democracy.newProposal.sendTransaction( recipient, amount, '', shortNote, {from: eth.accounts[0], gas:1000000})
|
|
||||||
|
|
||||||
After a minute, anyone can check the proposal recipient and amount by executing these commands:
|
|
||||||
|
|
||||||
"This organization has " + (Number(democracy.numProposals())+1) + " pending proposals";
|
|
||||||
|
|
||||||
### Keep an eye on the organization
|
|
||||||
|
|
||||||
Unlike most governments, your country's government is completely transparent and easily programmable. As a small demonstration here's a snippet of code that goes through all the current proposals and prints what they are and for whom:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function checkAllProposals() {
|
|
||||||
console.log("Country Balance: " + web3.fromWei( eth.getBalance(democracy.address), "ether") );
|
|
||||||
for (i = 0; i< (Number(democracy.numProposals())); i++ ) {
|
|
||||||
var p = democracy.proposals(i);
|
|
||||||
var timeleft = Math.floor(((Math.floor(Date.now() / 1000)) - Number(p[4]) - Number(democracy.debatingPeriod()))/60);
|
|
||||||
console.log("Proposal #" + i + " Send " + web3.fromWei( p[1], "ether") + " ether to address " + p[0].substring(2,6) + " for "+ p[3] + ".\t Deadline:"+ Math.abs(Math.floor(timeleft)) + (timeleft>0?" minutes ago ":" minutes left ") + (p[5]? " Active":" Archived") );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAllProposals();
|
|
||||||
|
|
||||||
A concerned citizen could easily write a bot that periodically pings the blockchain and then publicizes any new proposals that were put forth, guaranteeing total transparency.
|
|
||||||
|
|
||||||
Now of course you want other people to be able to vote on your proposals. You can check the crowdsale tutorial on the best way to register your contract app so that all the user needs is a name, but for now let's use the easier version. Anyone should be able to instantiate a local copy of your country in their computer by using this giant command:
|
|
||||||
|
|
||||||
|
|
||||||
democracy = eth.contract( [{ constant: true, inputs: [{ name: '', type: 'uint256' } ], name: 'proposals', outputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'data', type: 'bytes32' }, { name: 'descriptionHash', type: 'bytes32' }, { name: 'creationDate', type: 'uint256' }, { name: 'numVotes', type: 'uint256' }, { name: 'quorum', type: 'uint256' }, { name: 'active', type: 'bool' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' } ], name: 'executeProposal', outputs: [{ name: 'result', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'debatingPeriod', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'numProposals', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'founder', outputs: [{ name: '', type: 'address' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' }, { name: '_position', type: 'int256' } ], name: 'vote', outputs: [{ name: 'voteID', type: 'uint256' } ], type: 'function' }, { constant: false, inputs: [{ name: '_voterShareAddress', type: 'address' } ], name: 'setup', outputs: [ ], type: 'function' }, { constant: false, inputs: [{ name: '_recipient', type: 'address' }, { name: '_amount', type: 'uint256' }, { name: '_data', type: 'bytes32' }, { name: '_descriptionHash', type: 'bytes32' } ], name: 'newProposal', outputs: [{ name: 'proposalID', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'minimumQuorum', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { inputs: [ ], type: 'constructor' } ] ).at(registrar.addr('MyPersonalCountry'))
|
|
||||||
|
|
||||||
Then anyone who owns any of your tokens can vote on the proposals by doing this:
|
|
||||||
|
|
||||||
var proposalID = 0;
|
|
||||||
var position = -1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
|
|
||||||
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});
|
|
||||||
|
|
||||||
var proposalID = 1;
|
|
||||||
var position = 1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
|
|
||||||
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});
|
|
||||||
|
|
||||||
|
|
||||||
Unless you changed the basic parameters in the code, any proposal will have to be debated for at least a week until it can be executed. After that anyone—even a non-citizen—can demand the votes to be counted and the proposal to be executed. The votes are tallied and weighted at that moment and if the proposal is accepted then the ether is sent immediately and the proposal is archived. If the votes end in a tie or the minimum quorum hasn’t been reached, the voting is kept open until the stalemate is resolved. If it loses, then it's archived and cannot be voted again.
|
|
||||||
|
|
||||||
var proposalID = 1;
|
|
||||||
democracy.executeProposal.sendTransaction(proposalID, {from: eth.accounts[0], gas: 1000000});
|
|
||||||
|
|
||||||
|
|
||||||
If the proposal passed then you should be able to see Bob's ethers arriving on his address:
|
|
||||||
|
|
||||||
web3.fromWei(eth.getBalance(democracy.address), "ether") + " ether";
|
|
||||||
web3.fromWei(eth.getBalance(registrar.addr("bob")), "ether") + " ether";
|
|
||||||
|
|
||||||
|
|
||||||
**Try for yourself:** This is a very simple democracy contract, which could be vastly improved: currently, all proposals have the same debating time and are won by direct vote and simple majority. Can you change that so it will have some situations, depending on the amount proposed, that the debate might be longer or that it would require a larger majority? Also think about some way where citizens didn't need to vote on every issue and could temporarily delegate their votes to a special representative. You might have also noticed that we added a tiny description for each proposal. This could be used as a title for the proposal or could be a hash of a larger document describing it in detail.
|
|
||||||
|
|
||||||
### Let's go exploring!
|
|
||||||
|
|
||||||
You have reached the end of this tutorial, but it's just the beginning of a great adventure. Look back and see how much you accomplished: you created a living, talking robot, your own cryptocurrency, raised funds through a trustless crowdfunding and used it to kickstart your own personal democratic organization.
|
|
||||||
|
|
||||||
For the sake of simplicity, we only used the democratic organization you created to send ether around, the native currency of ethereum. While that might be good enough for some, this is only scratching the surface of what can be done. In the ethereum network contracts have all the same rights as any normal user, meaning that your organization could do any of the transactions that you executed coming from your own accounts.
|
|
||||||
|
|
||||||
|
|
||||||
### What could happen next?
|
|
||||||
|
|
||||||
* The greeter contract you created at the beginning could be improved to charge ether for its services and could funnel those funds into the DAO.
|
|
||||||
|
|
||||||
* The tokens you still control could be sold on a decentralized exchange or traded for goods and services to fund further develop the first contract and grow the organization.
|
|
||||||
|
|
||||||
* Your DAO could own its own name on the name registrar, and then change where it's redirecting in order to update itself if the token holders approved.
|
|
||||||
|
|
||||||
* The organization could hold not only ethers, but any kind of other coin created on ethereum, including assets whose value are tied to the bitcoin or dollar.
|
|
||||||
|
|
||||||
* The DAO could be programmed to allow a proposal with multiple transactions, some scheduled to the future.
|
|
||||||
It could also own shares of other DAO's, meaning it could vote on larger organization or be a part of a federation of DAO's.
|
|
||||||
|
|
||||||
* The Token Contract could be reprogrammed to hold ether or to hold other tokens and distribute it to the token holders. This would link the value of the token to the value of other assets, so paying dividends could be accomplished by simply moving funds to the token address.
|
|
||||||
|
|
||||||
This all means that this tiny society you created could grow, get funding from third parties, pay recurrent salaries, own any kind of crypto-assets and even use crowdsales to fund its activities. All with full transparency, complete accountability and complete immunity from any human interference. While the network lives the contracts will execute exactly the code they were created to execute, without any exception, forever.
|
|
||||||
|
|
||||||
So what will your contract be? Will it be a country, a company, a non-profit group? What will your code do?
|
|
||||||
|
|
||||||
That's up to you.
|
|
|
@ -1,350 +0,0 @@
|
||||||
---
|
|
||||||
title: Managing your accounts
|
|
||||||
---
|
|
||||||
**WARNING**
|
|
||||||
Remember your password.
|
|
||||||
|
|
||||||
If you lose the password you use to encrypt your account, you will not be able to access that account.
|
|
||||||
Repeat: It is NOT possible to access your account without a password and there is no _forgot my password_ option here. Do not forget it.
|
|
||||||
|
|
||||||
The ethereum CLI `geth` provides account management via the `account` command:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account <command> [options...] [arguments...]
|
|
||||||
```
|
|
||||||
|
|
||||||
Manage accounts lets you create new accounts, list all existing accounts, import a private
|
|
||||||
key into a new account, migrate to newest key format and change your password.
|
|
||||||
|
|
||||||
It supports interactive mode, when you are prompted for password as well as
|
|
||||||
non-interactive mode where passwords are supplied via a given password file.
|
|
||||||
Non-interactive mode is only meant for scripted use on test networks or known safe
|
|
||||||
environments.
|
|
||||||
|
|
||||||
Make sure you remember the password you gave when creating a new account (with new, update
|
|
||||||
or import). Without it you are not able to unlock your account.
|
|
||||||
|
|
||||||
Note that exporting your key in unencrypted format is NOT supported.
|
|
||||||
|
|
||||||
Keys are stored under `<DATADIR>/keystore`. Make sure you backup your keys regularly! See
|
|
||||||
[DATADIR backup & restore](../doc/Backup--restore)
|
|
||||||
for more information. If a custom datadir and keystore option are given the keystore
|
|
||||||
option takes preference over the datadir option.
|
|
||||||
|
|
||||||
The newest format of the keyfiles is: `UTC--<created_at UTC ISO8601>-<address hex>`. The
|
|
||||||
order of accounts when listing, is lexicographic, but as a consequence of the timespamp
|
|
||||||
format, it is actually order of creation
|
|
||||||
|
|
||||||
It is safe to transfer the entire directory or the individual keys therein between
|
|
||||||
ethereum nodes. Note that in case you are adding keys to your node from a different node,
|
|
||||||
the order of accounts may change. So make sure you do not rely or change the index in your
|
|
||||||
scripts or code snippets.
|
|
||||||
|
|
||||||
And again. **DO NOT FORGET YOUR PASSWORD**
|
|
||||||
|
|
||||||
```
|
|
||||||
COMMANDS:
|
|
||||||
list Print summary of existing accounts
|
|
||||||
new Create a new account
|
|
||||||
update Update an existing account
|
|
||||||
import Import a private key into a new account
|
|
||||||
```
|
|
||||||
|
|
||||||
You can get info about subcommands by `geth account <command> --help`.
|
|
||||||
```
|
|
||||||
$ geth account list --help
|
|
||||||
list [command options] [arguments...]
|
|
||||||
|
|
||||||
Print a short summary of all accounts
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
--datadir "/home/bas/.ethereum" Data directory for the databases and keystore
|
|
||||||
--keystore Directory for the keystore (default = inside the datadir)
|
|
||||||
```
|
|
||||||
|
|
||||||
Accounts can also be managed via the [Javascript Console](../interface/JavaScript-Console)
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
### Interactive use
|
|
||||||
|
|
||||||
#### creating an account
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account new
|
|
||||||
Your new account is locked with a password. Please give a password. Do not forget this password.
|
|
||||||
Passphrase:
|
|
||||||
Repeat Passphrase:
|
|
||||||
Address: {168bc315a2ee09042d83d7c5811b533620531f67}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Listing accounts in a custom keystore directory
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account list --keystore /tmp/mykeystore/
|
|
||||||
Account #0: {5afdd78bdacb56ab1dad28741ea2a0e47fe41331} keystore:///tmp/mykeystore/UTC--2017-04-28T08-46-27.437847599Z--5afdd78bdacb56ab1dad28741ea2a0e47fe41331
|
|
||||||
Account #1: {9acb9ff906641a434803efb474c96a837756287f} keystore:///tmp/mykeystore/UTC--2017-04-28T08-46-52.180688336Z--9acb9ff906641a434803efb474c96a837756287f
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Import private key into a node with a custom datadir
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account import --datadir /someOtherEthDataDir ./key.prv
|
|
||||||
The new account will be encrypted with a passphrase.
|
|
||||||
Please enter a passphrase now.
|
|
||||||
Passphrase:
|
|
||||||
Repeat Passphrase:
|
|
||||||
Address: {7f444580bfef4b9bc7e14eb7fb2a029336b07c9d}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Account update
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account update a94f5374fce5edbc8e2a8697c15331677e6ebf0b
|
|
||||||
Unlocking account a94f5374fce5edbc8e2a8697c15331677e6ebf0b | Attempt 1/3
|
|
||||||
Passphrase:
|
|
||||||
0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b
|
|
||||||
Account 'a94f5374fce5edbc8e2a8697c15331677e6ebf0b' unlocked.
|
|
||||||
Please give a new password. Do not forget this password.
|
|
||||||
Passphrase:
|
|
||||||
Repeat Passphrase:
|
|
||||||
0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b
|
|
||||||
```
|
|
||||||
|
|
||||||
### Non-interactive use
|
|
||||||
|
|
||||||
You supply a plaintext password file as argument to the `--password` flag. The data in the
|
|
||||||
file consists of the raw characters of the password, followed by a single newline.
|
|
||||||
|
|
||||||
**Note**: Supplying the password directly as part of the command line is not recommended,
|
|
||||||
but you can always use shell trickery to get round this restriction.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account new --password /path/to/password
|
|
||||||
|
|
||||||
$ geth account import --datadir /someOtherEthDataDir --password /path/to/anotherpassword ./key.prv
|
|
||||||
```
|
|
||||||
|
|
||||||
# Creating accounts
|
|
||||||
|
|
||||||
## Creating a new account
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account new
|
|
||||||
$ geth account new --password /path/to/passwdfile
|
|
||||||
$ geth account new --password <(echo $mypassword)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Creates a new account and prints the address.
|
|
||||||
|
|
||||||
On the console, use:
|
|
||||||
|
|
||||||
```
|
|
||||||
> personal.NewAccount()
|
|
||||||
... you will be prompted for a password ...
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
> personal.newAccount("passphrase")
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
The account is saved in encrypted format. You **must** remember this passphrase to unlock
|
|
||||||
your account in the future.
|
|
||||||
|
|
||||||
For non-interactive use the passphrase can be specified with the `--password` flag:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth account new --password <passwordfile>
|
|
||||||
```
|
|
||||||
|
|
||||||
Note, this is meant to be used for testing only, it is a bad idea to save your
|
|
||||||
password to file or expose in any other way.
|
|
||||||
|
|
||||||
## Creating an account by importing a private key
|
|
||||||
|
|
||||||
```
|
|
||||||
geth account import <keyfile>
|
|
||||||
```
|
|
||||||
|
|
||||||
Imports an unencrypted private key from `<keyfile>` and creates a new account and prints
|
|
||||||
the address.
|
|
||||||
|
|
||||||
The keyfile is assumed to contain an unencrypted private key as canonical EC raw bytes
|
|
||||||
encoded into hex.
|
|
||||||
|
|
||||||
The account is saved in encrypted format, you are prompted for a passphrase.
|
|
||||||
|
|
||||||
You must remember this passphrase to unlock your account in the future.
|
|
||||||
|
|
||||||
For non-interactive use the passphrase can be specified with the `--password` flag:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth account import --password <passwordfile> <keyfile>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: Since you can directly copy your encrypted accounts to another ethereum
|
|
||||||
instance, this import/export mechanism is not needed when you transfer an account between
|
|
||||||
nodes.
|
|
||||||
|
|
||||||
**Warning:** when you copy keys into an existing node's keystore, the order of accounts
|
|
||||||
you are used to may change. Therefore you make sure you either do not rely on the account
|
|
||||||
order or doublecheck and update the indexes used in your scripts.
|
|
||||||
|
|
||||||
**Warning:** If you use the password flag with a password file, best to make sure the file
|
|
||||||
is not readable or even listable for anyone but you. You achieve this with:
|
|
||||||
|
|
||||||
```
|
|
||||||
touch /path/to/password
|
|
||||||
chmod 700 /path/to/password
|
|
||||||
cat > /path/to/password
|
|
||||||
>I type my pass here^D
|
|
||||||
```
|
|
||||||
|
|
||||||
## Updating an existing account
|
|
||||||
|
|
||||||
You can update an existing account on the command line with the `update` subcommand with
|
|
||||||
the account address or index as parameter. You can specify multiple accounts at once.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth account update 5afdd78bdacb56ab1dad28741ea2a0e47fe41331 9acb9ff906641a434803efb474c96a837756287f
|
|
||||||
geth account update 0 1 2
|
|
||||||
```
|
|
||||||
|
|
||||||
The account is saved in the newest version in encrypted format, you are prompted
|
|
||||||
for a passphrase to unlock the account and another to save the updated file.
|
|
||||||
|
|
||||||
This same command can therefore be used to migrate an account of a deprecated
|
|
||||||
format to the newest format or change the password for an account.
|
|
||||||
|
|
||||||
After a successful update, all previous formats/versions of that same key are removed!
|
|
||||||
|
|
||||||
# Importing your presale wallet
|
|
||||||
|
|
||||||
Importing your presale wallet is very easy. If you remember your password that is:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth wallet import /path/to/my/presale.wallet
|
|
||||||
```
|
|
||||||
|
|
||||||
will prompt for your password and imports your ether presale account. It can be used
|
|
||||||
non-interactively with the --password option taking a passwordfile as argument containing
|
|
||||||
the wallet password in cleartext.
|
|
||||||
|
|
||||||
# Listing accounts and checking balances
|
|
||||||
|
|
||||||
### Listing your current accounts
|
|
||||||
|
|
||||||
From the command line, call the CLI with:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ geth account list
|
|
||||||
Account #0: {5afdd78bdacb56ab1dad28741ea2a0e47fe41331} keystore:///tmp/mykeystore/UTC--2017-04-28T08-46-27.437847599Z--5afdd78bdacb56ab1dad28741ea2a0e47fe41331
|
|
||||||
Account #1: {9acb9ff906641a434803efb474c96a837756287f} keystore:///tmp/mykeystore/UTC--2017-04-28T08-46-52.180688336Z--9acb9ff906641a434803efb474c96a837756287f
|
|
||||||
```
|
|
||||||
|
|
||||||
to list your accounts in order of creation.
|
|
||||||
|
|
||||||
**Note**:
|
|
||||||
This order can change if you copy keyfiles from other nodes, so make sure you either do not rely on indexes or make sure if you copy keys you check and update your account indexes in your scripts.
|
|
||||||
|
|
||||||
When using the console:
|
|
||||||
```
|
|
||||||
> eth.accounts
|
|
||||||
["0x5afdd78bdacb56ab1dad28741ea2a0e47fe41331", "0x9acb9ff906641a434803efb474c96a837756287f"]
|
|
||||||
```
|
|
||||||
|
|
||||||
or via RPC:
|
|
||||||
```
|
|
||||||
# Request
|
|
||||||
$ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1} http://127.0.0.1:8545'
|
|
||||||
|
|
||||||
# Result
|
|
||||||
{
|
|
||||||
"id":1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": ["0x5afdd78bdacb56ab1dad28741ea2a0e47fe41331", "0x9acb9ff906641a434803efb474c96a837756287f"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to use an account non-interactively, you need to unlock it. You can do this on
|
|
||||||
the command line with the `--unlock` option which takes a comma separated list of accounts
|
|
||||||
(in hex or index) as argument so you can unlock the accounts programmatically for one
|
|
||||||
session. This is useful if you want to use your account from Dapps via RPC. `--unlock `
|
|
||||||
will unlock the first account. This is useful when you created your account
|
|
||||||
programmatically, you do not need to know the actual account to unlock it.
|
|
||||||
|
|
||||||
Create account and start node with account unlocked:
|
|
||||||
```
|
|
||||||
geth account new --password <(echo this is not secret!)
|
|
||||||
geth --password <(echo this is not secret!) --unlock primary --rpccorsdomain localhost --verbosity 6 2>> geth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
Instead of the account address, you can use integer indexes which refers to the address
|
|
||||||
position in the account listing (and corresponds to order of creation)
|
|
||||||
|
|
||||||
The command line allows you to unlock multiple accounts. In this case the argument to
|
|
||||||
unlock is a comma delimited list of accounts addresses or indexes.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --unlock "0x407d73d8a49eeb85d32cf465507dd71d507100c1,0,5,e470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32"
|
|
||||||
```
|
|
||||||
|
|
||||||
If this construction is used non-interactively, your password file will need to contain
|
|
||||||
the respective passwords for the accounts in question, one per line.
|
|
||||||
|
|
||||||
On the console you can also unlock accounts (one at a time) for a duration (in seconds).
|
|
||||||
|
|
||||||
```
|
|
||||||
personal.unlockAccount(address, "password", 300)
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that we do NOT recommend using the password argument here, since the console history
|
|
||||||
is logged, so you may compromise your account. You have been warned.
|
|
||||||
|
|
||||||
### Checking account balances
|
|
||||||
|
|
||||||
To check your the etherbase account balance:
|
|
||||||
```
|
|
||||||
> web3.fromWei(eth.getBalance(eth.coinbase), "ether")
|
|
||||||
6.5
|
|
||||||
```
|
|
||||||
|
|
||||||
Print all balances with a JavaScript function:
|
|
||||||
```
|
|
||||||
function checkAllBalances() {
|
|
||||||
var totalBal = 0;
|
|
||||||
for (var acctNum in eth.accounts) {
|
|
||||||
var acct = eth.accounts[acctNum];
|
|
||||||
var acctBal = web3.fromWei(eth.getBalance(acct), "ether");
|
|
||||||
totalBal += parseFloat(acctBal);
|
|
||||||
console.log(" eth.accounts[" + acctNum + "]: \t" + acct + " \tbalance: " + acctBal + " ether");
|
|
||||||
}
|
|
||||||
console.log(" Total balance: " + totalBal + " ether");
|
|
||||||
};
|
|
||||||
```
|
|
||||||
That can then be executed with:
|
|
||||||
```
|
|
||||||
> checkAllBalances();
|
|
||||||
eth.accounts[0]: 0xd1ade25ccd3d550a7eb532ac759cac7be09c2719 balance: 63.11848 ether
|
|
||||||
eth.accounts[1]: 0xda65665fc30803cb1fb7e6d86691e20b1826dee0 balance: 0 ether
|
|
||||||
eth.accounts[2]: 0xe470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32 balance: 1 ether
|
|
||||||
eth.accounts[3]: 0xf4dd5c3794f1fd0cdc0327a83aa472609c806e99 balance: 6 ether
|
|
||||||
```
|
|
||||||
|
|
||||||
Since this function will disappear after restarting geth, it can be helpful to store
|
|
||||||
commonly used functions to be recalled later. The
|
|
||||||
[loadScript](../interface/JavaScript-Console#loadscript)
|
|
||||||
function makes this very easy.
|
|
||||||
|
|
||||||
First, save the `checkAllBalances()` function definition to a file on your computer. For
|
|
||||||
example, `/Users/username/gethload.js`. Then load the file from the interactive console:
|
|
||||||
|
|
||||||
```
|
|
||||||
> loadScript("/Users/username/gethload.js")
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
The file will modify your JavaScript environment as if you has typed the commands
|
|
||||||
manually. Feel free to experiment!
|
|
|
@ -1,294 +0,0 @@
|
||||||
---
|
|
||||||
title: Mining
|
|
||||||
---
|
|
||||||
* [Introduction to Ethereum mining](https://github.com/ethereum/wiki/wiki/Mining#introduction) _(main wiki)_
|
|
||||||
|
|
||||||
# CPU Mining with Geth
|
|
||||||
|
|
||||||
At Frontier, the first release of Ethereum, you'll just need a) a GPU and b) an Ethereum client, Geth. CPU mining will be possible but too inefficient to hold any value.
|
|
||||||
|
|
||||||
At the moment, Geth only includes a CPU miner, and the team is testing a [GPU miner branch](https://github.com/ethereum/go-ethereum/tree/gpu_miner), but this won't be part of Frontier.
|
|
||||||
|
|
||||||
The C++ implementation of Ethereum also offers a GPU miner, both as part of Eth (its CLI), AlethZero (its GUI) and EthMiner (the standalone miner).
|
|
||||||
|
|
||||||
_**NOTE:** Ensure your blockchain is fully synchronised with the main chain before starting to mine, otherwise you will not be mining on the main chain._
|
|
||||||
|
|
||||||
When you start up your ethereum node with `geth` it is not mining by default. To start it in mining mode, you use the `--mine` [command line option](../interface/Command-Line-Options). The `-minerthreads` parameter can be used to set the number parallel mining threads (defaulting to the total number of processor cores).
|
|
||||||
|
|
||||||
`geth --mine --minerthreads=4`
|
|
||||||
|
|
||||||
You can also start and stop CPU mining at runtime using the [console](../interface/JavaScript-Console#adminminerstart). `miner.start` takes an optional parameter for the number of miner threads.
|
|
||||||
|
|
||||||
```
|
|
||||||
> miner.start(8)
|
|
||||||
true
|
|
||||||
> miner.stop()
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that mining for real ether only makes sense if you are in sync with the network (since you mine on top of the consensus block). Therefore the eth blockchain downloader/synchroniser will delay mining until syncing is complete, and after that mining automatically starts unless you cancel your intention with `miner.stop()`.
|
|
||||||
|
|
||||||
In order to earn ether you must have your **etherbase** (or **coinbase**) address set. This etherbase defaults to your [primary account](Managing-your-accounts). If you don't have an etherbase address, then `geth --mine` will not start up.
|
|
||||||
|
|
||||||
You can set your etherbase on the command line:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --etherbase 1 --mine 2>> geth.log // 1 is index: second account by creation order OR
|
|
||||||
geth --etherbase '0xa4d8e9cae4d04b093aac82e6cd355b6b963fb7ff' --mine 2>> geth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
You can reset your etherbase on the console too:
|
|
||||||
```
|
|
||||||
miner.setEtherbase(eth.accounts[2])
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that your etherbase does not need to be an address of a local account, just an existing one.
|
|
||||||
|
|
||||||
There is an option [to add extra Data](../interface/JavaScript-Console#adminminersetextra) (32 bytes only) to your mined blocks. By convention this is interpreted as a unicode string, so you can set your short vanity tag.
|
|
||||||
|
|
||||||
```
|
|
||||||
miner.setExtra("ΞTHΞЯSPHΞЯΞ")
|
|
||||||
...
|
|
||||||
debug.printBlock(131805)
|
|
||||||
BLOCK(be465b020fdbedc4063756f0912b5a89bbb4735bd1d1df84363e05ade0195cb1): Size: 531.00 B TD: 643485290485 {
|
|
||||||
NoNonce: ee48752c3a0bfe3d85339451a5f3f411c21c8170353e450985e1faab0a9ac4cc
|
|
||||||
Header:
|
|
||||||
[
|
|
||||||
...
|
|
||||||
Coinbase: a4d8e9cae4d04b093aac82e6cd355b6b963fb7ff
|
|
||||||
Number: 131805
|
|
||||||
Extra: ΞTHΞЯSPHΞЯΞ
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See also [this proposal](https://github.com/ethereum/wiki/wiki/Extra-Data)
|
|
||||||
|
|
||||||
You can check your hashrate with [miner.hashrate](../interface/JavaScript-Console#adminminerhashrate), the result is in H/s (Hash operations per second).
|
|
||||||
|
|
||||||
```
|
|
||||||
> miner.hashrate
|
|
||||||
712000
|
|
||||||
```
|
|
||||||
|
|
||||||
After you successfully mined some blocks, you can check the ether balance of your etherbase account. Now assuming your etherbase is a local account:
|
|
||||||
|
|
||||||
```
|
|
||||||
> eth.getBalance(eth.coinbase).toNumber();
|
|
||||||
'34698870000000'
|
|
||||||
```
|
|
||||||
|
|
||||||
In order to spend your earnings you will need to have this account unlocked.
|
|
||||||
|
|
||||||
```
|
|
||||||
> personal.unlockAccount(eth.coinbase)
|
|
||||||
Password
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
You can check which blocks are mined by a particular miner (address) with the following code snippet on the console:
|
|
||||||
|
|
||||||
```
|
|
||||||
function minedBlocks(lastn, addr) {
|
|
||||||
addrs = [];
|
|
||||||
if (!addr) {
|
|
||||||
addr = eth.coinbase
|
|
||||||
}
|
|
||||||
limit = eth.blockNumber - lastn
|
|
||||||
for (i = eth.blockNumber; i >= limit; i--) {
|
|
||||||
if (eth.getBlock(i).miner == addr) {
|
|
||||||
addrs.push(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
// scans the last 1000 blocks and returns the blocknumbers of blocks mined by your coinbase
|
|
||||||
// (more precisely blocks the mining reward for which is sent to your coinbase).
|
|
||||||
minedBlocks(1000, eth.coinbase);
|
|
||||||
//[352708, 352655, 352559]
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that it will happen often that you find a block yet it never makes it to the canonical chain. This means when you locally include your mined block, the current state will show the mining reward credited to your account, however, after a while, the better chain is discovered and we switch to a chain in which your block is not included and therefore no mining reward is credited. Therefore it is quite possible that as a miner monitoring their coinbase balance will find that it may fluctuate quite a bit.
|
|
||||||
|
|
||||||
The logs show locally mined blocks confirmed after 5 blocks. At the moment you may find it easier and faster to generate the list of your mined blocks from these logs.
|
|
||||||
|
|
||||||
Mining success depends on the set block difficulty. Block difficulty dynamically adjusts each block in order to regulate the network hashing power to produce a 12 second blocktime. Your chances of finding a block therefore follows from your hashrate relative to difficulty. The time you need to wait you are expected to find a block can be estimated with the following code:
|
|
||||||
|
|
||||||
**INCORRECT...CHECKING**
|
|
||||||
```
|
|
||||||
etm = eth.getBlock("latest").difficulty/miner.hashrate; // estimated time in seconds
|
|
||||||
Math.floor(etm / 3600.) + "h " + Math.floor((etm % 3600)/60) + "m " + Math.floor(etm % 60) + "s";
|
|
||||||
// 1h 3m 30s
|
|
||||||
```
|
|
||||||
|
|
||||||
Given a difficulty of 3 billion, a typical CPU with 800KH/s is expected to find a block every ....?
|
|
||||||
|
|
||||||
|
|
||||||
# GPU mining
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
## Hardware
|
|
||||||
|
|
||||||
The algorithm is memory hard and in order to fit the DAG into memory, it needs 1-2GB of RAM on each GPU. If you get ` Error GPU mining. GPU memory fragmentation?` you havent got enough memory.
|
|
||||||
|
|
||||||
The GPU miner is implemented in OpenCL, so AMD GPUs will be 'faster' than same-category NVIDIA GPUs.
|
|
||||||
|
|
||||||
ASICs and FPGAs are relatively inefficient and therefore discouraged.
|
|
||||||
|
|
||||||
To get openCL for your chipset and platform, try:
|
|
||||||
* [AMD SDK openCL](http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk)
|
|
||||||
* [NVIDIA CUDA openCL](https://developer.nvidia.com/cuda-downloads)
|
|
||||||
|
|
||||||
## On Ubuntu
|
|
||||||
### AMD
|
|
||||||
|
|
||||||
* http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing
|
|
||||||
* http://developer.amd.com/tools-and-sdks/graphics-development/display-library-adl-sdk/
|
|
||||||
|
|
||||||
download: `ADL_SDK8.zip ` and `AMD-APP-SDK-v2.9-1.599.381-GA-linux64.sh`
|
|
||||||
|
|
||||||
```
|
|
||||||
./AMD-APP-SDK-v2.9-1.599.381-GA-linux64.sh
|
|
||||||
ln -s /opt/AMDAPPSDK-2.9-1 /opt/AMDAPP
|
|
||||||
ln -s /opt/AMDAPP/include/CL /usr/include
|
|
||||||
ln -s /opt/AMDAPP/lib/x86_64/* /usr/lib/
|
|
||||||
ldconfig
|
|
||||||
reboot
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
apt-get install fglrx-updates
|
|
||||||
// wget, tar, opencl
|
|
||||||
sudo aticonfig --adapter=all --initial
|
|
||||||
sudo aticonfig --list-adapters
|
|
||||||
* 0. 01:00.0 AMD Radeon R9 200 Series
|
|
||||||
|
|
||||||
* - Default adapter
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nvidia
|
|
||||||
The following instructions are, for the most part, relevant to any system with Ubuntu 14.04 and a Nvidia GPU.
|
|
||||||
[Setting up an EC2 instance for mining](https://forum.ethereum.org/discussion/comment/8889/#Comment_8889)
|
|
||||||
|
|
||||||
## On MacOSx
|
|
||||||
|
|
||||||
```
|
|
||||||
wget http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.29_mac.pkg
|
|
||||||
sudo installer -pkg ~/Desktop/cuda_7.0.29_mac.pkg -target /
|
|
||||||
brew update
|
|
||||||
brew tap ethereum/ethereum
|
|
||||||
brew reinstall cpp-ethereum --with-gpu-mining --devel --headless --build-from-source
|
|
||||||
```
|
|
||||||
|
|
||||||
You check your cooling status:
|
|
||||||
|
|
||||||
aticonfig --adapter=0 --od-gettemperature
|
|
||||||
|
|
||||||
## Mining Software
|
|
||||||
|
|
||||||
The official Frontier release of `geth` only supports a CPU miner natively. We are working on a [GPU miner](https://github.com/ethereum/go-ethereum/tree/gpuminer), but it may not be available for the Frontier release. Geth however can be used in conjunction with `ethminer`, using the standalone miner as workers and `geth` as scheduler communicating via [JSON-RPC](https://github.com/ethereum/wiki/JSON-RPC).
|
|
||||||
|
|
||||||
The [C++ implementation of Ethereum](https://github.com/ethereum/cpp-ethereum/) (not officially released) however has a GPU miner. It can be used from `eth`, `AlethZero` (GUI) and `ethMiner` (the standalone miner).
|
|
||||||
|
|
||||||
[You can install this](https://github.com/ethereum/cpp-ethereum/wiki/Installing-clients) via ppa on linux, brew tap on MacOS or from source.
|
|
||||||
|
|
||||||
On MacOS:
|
|
||||||
```
|
|
||||||
brew install cpp-ethereum --with-gpu-mining --devel --build-from-source
|
|
||||||
```
|
|
||||||
|
|
||||||
On Linux:
|
|
||||||
```
|
|
||||||
apt-get install cpp-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
On Windows:
|
|
||||||
https://github.com/ethereum/cpp-ethereum/wiki/Building-on-Windows
|
|
||||||
|
|
||||||
## GPU mining with ethminer
|
|
||||||
To mine with `eth`:
|
|
||||||
|
|
||||||
```
|
|
||||||
eth -m on -G -a <coinbase> -i -v 8 //
|
|
||||||
```
|
|
||||||
|
|
||||||
To install `ethminer` from source:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd cpp-ethereum
|
|
||||||
cmake -DETHASHCL=1 -DGUI=0
|
|
||||||
make -j4
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
|
|
||||||
To set up GPU mining you need a coinbase account. It can be an account created locally or remotely.
|
|
||||||
|
|
||||||
### Using ethminer with geth
|
|
||||||
|
|
||||||
```
|
|
||||||
geth account new
|
|
||||||
geth --rpc --rpccorsdomain localhost 2>> geth.log &
|
|
||||||
ethminer -G // -G for GPU, -M for benchmark
|
|
||||||
tail -f geth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
`ethminer` communicates with geth on port 8545 (the default RPC port in geth). You can change this by giving the [`--rpcport` option](https://github.com/ethereum/go-ethereum/Command-Line-Options) to `geth`.
|
|
||||||
Ethminer will find get on any port. Note that you need to set the CORS header with `--rpccorsdomain localhost`. You can also set port on `ethminer` with `-F http://127.0.0.1:3301`. Setting the ports is necessary if you want several instances mining on the same computer, although this is somewhat pointless. If you are testing on a private cluster, we recommend you use CPU mining instead.
|
|
||||||
|
|
||||||
Also note that you do **not** need to give `geth` the `--mine` option or start the miner in the console unless you want to do CPU mining on TOP of GPU mining.
|
|
||||||
|
|
||||||
If the default for `ethminer` does not work try to specify the OpenCL device with: `--opencl-device X` where X is 0, 1, 2, etc.
|
|
||||||
When running `ethminer` with `-M` (benchmark), you should see something like:
|
|
||||||
|
|
||||||
Benchmarking on platform: { "platform": "NVIDIA CUDA", "device": "GeForce GTX 750 Ti", "version": "OpenCL 1.1 CUDA" }
|
|
||||||
|
|
||||||
|
|
||||||
Benchmarking on platform: { "platform": "Apple", "device": "Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz", "version": "OpenCL 1.2 " }
|
|
||||||
|
|
||||||
To debug `geth`:
|
|
||||||
|
|
||||||
```
|
|
||||||
geth --rpccorsdomain "localhost" --verbosity 6 2>> geth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
To debug the miner:
|
|
||||||
|
|
||||||
```
|
|
||||||
make -DCMAKE_BUILD_TYPE=Debug -DETHASHCL=1 -DGUI=0
|
|
||||||
gdb --args ethminer -G -M
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note** hashrate info is not available in `geth` when GPU mining. Check your hashrate with `ethminer`, `miner.hashrate` will always report 0.
|
|
||||||
|
|
||||||
|
|
||||||
### ethminer and eth
|
|
||||||
|
|
||||||
`ethminer` can be used in conjunction with `eth` via rpc
|
|
||||||
|
|
||||||
```
|
|
||||||
eth -i -v 8 -j // -j for rpc
|
|
||||||
ethminer -G -M // -G for GPU, -M for benchmark
|
|
||||||
tail -f geth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
or you can use `eth` to GPU mine by itself:
|
|
||||||
|
|
||||||
```
|
|
||||||
eth -m on -G -a <coinbase> -i -v 8 //
|
|
||||||
```
|
|
||||||
|
|
||||||
# Further Resources:
|
|
||||||
|
|
||||||
* [ether-proxy, a web interface for mining rigs](https://github.com/sammy007/ether-proxy)
|
|
||||||
(supports solo and pool mining proxy with web interface and rigs availability monitoring)
|
|
||||||
* [ethereum forum mining FAQ live update](https://forum.ethereum.org/discussion/197/mining-faq-live-updates)
|
|
||||||
* [yates randall mining video](https://www.youtube.com/watch?v=CnKnclkkbKg)
|
|
||||||
* https://blog.ethereum.org/2014/07/05/stake/
|
|
||||||
* https://blog.ethereum.org/2014/10/03/slasher-ghost-developments-proof-stake/
|
|
||||||
* https://blog.ethereum.org/2014/06/19/mining/
|
|
||||||
* https://github.com/ethereum/wiki/wiki/Ethash
|
|
||||||
* [Benchmarking results for GPU mining](https://forum.ethereum.org/discussion/2134/gpu-mining-is-out-come-and-let-us-know-of-your-bench-scores)
|
|
||||||
* [historic moment](https://twitter.com/gavofyork/status/586623875577937922)
|
|
||||||
* [live mining statistic](https://etherapps.info/stats/mining)
|
|
||||||
* [netstat ethereum network monitor](https://stats.ethdev.com)
|
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
title: Building Ethereum
|
|
||||||
---
|
|
||||||
## Installation Instructions
|
|
||||||
|
|
||||||
Follow the appropriate link below to find installation instructions for
|
|
||||||
your platform.
|
|
||||||
|
|
||||||
* [Installation Instructions for Mac OS X](../doc/Installation-Instructions-for-Mac)
|
|
||||||
* [Installation Instructions for Windows](../doc/Installation-instructions-for-Windows)
|
|
||||||
* Installation Instructions for Linux/Unix
|
|
||||||
* [Ubuntu](../doc/Installation-Instructions-for-Ubuntu)
|
|
||||||
* [Arch](../doc/Installation-Instructions-for-Arch)
|
|
||||||
* [FreeBSD](../doc/Installation-Instructions-for-FreeBSD)
|
|
||||||
* [Setup for Raspberry Pi](https://github.com/ethereum/wiki/wiki/Raspberry-Pi-instructions)
|
|
||||||
* [ARM](../doc/Installation-Instructions-for-ARM)
|
|
||||||
* [Usage instructions for Docker](../doc/Running-in-Docker)
|
|
||||||
|
|
||||||
## Quick Links
|
|
||||||
|
|
||||||
* [Ubuntu PPA](https://launchpad.net/~ethereum/+archive/ubuntu/ethereum)
|
|
||||||
* [Download Page](https://geth.ethereum.org/downloads)
|
|
|
@ -1,141 +0,0 @@
|
||||||
---
|
|
||||||
title: Developers' guide
|
|
||||||
---
|
|
||||||
**NOTE: These instructions are for people who want to contribute Go source code changes.
|
|
||||||
If you just want to run ethereum, use the normal [Installation Instructions](Building-Ethereum)**
|
|
||||||
|
|
||||||
This document is the entry point for developers of the Go implementation of Ethereum. Developers here refer to the hands-on: who are interested in build, develop, debug, submit a bug report or pull request or contribute code to go-ethereum.
|
|
||||||
|
|
||||||
## Building and Testing
|
|
||||||
|
|
||||||
### Go Environment
|
|
||||||
|
|
||||||
We assume that you have [`go` v1.8 installed](../doc/Installing-Go), and `GOPATH` is set.
|
|
||||||
|
|
||||||
**Note**:You must have your working copy under `$GOPATH/src/github.com/ethereum/go-ethereum`.
|
|
||||||
|
|
||||||
Since `go` does not use relative path for import, working in any other directory will have no effect, since the import paths will be appended to `$GOPATH/src`, and if the lib does not exist, the version at master HEAD will be downloaded.
|
|
||||||
|
|
||||||
Most likely you will be working from your fork of `go-ethereum`, let's say from `github.com/nirname/go-ethereum`. Clone or move your fork into the right place:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone git@github.com:nirname/go-ethereum.git $GOPATH/src/github.com/ethereum/go-ethereum
|
|
||||||
```
|
|
||||||
|
|
||||||
### Managing Vendored Dependencies
|
|
||||||
|
|
||||||
All other dependencies are tracked in the vendor/ directory. We use [govendor](https://github.com/kardianos/govendor) to manage them.
|
|
||||||
|
|
||||||
If you want to add a new dependency, run `govendor fetch <import-path>`, then commit the result.
|
|
||||||
|
|
||||||
If you want to update all dependencies to their latest upstream version, run `govendor fetch +v`.
|
|
||||||
|
|
||||||
You can also use govendor to run certain commands on all go-ethereum packages, excluding vendored
|
|
||||||
code. Example: to recreate all generated code, run `govendor generate +l`.
|
|
||||||
|
|
||||||
### Building Executables
|
|
||||||
|
|
||||||
Switch to the go-ethereum repository root directory.
|
|
||||||
|
|
||||||
You can build all code 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
|
|
||||||
```
|
|
||||||
|
|
||||||
Read about cross compilation of go-ethereum [here](../doc/Cross-compiling-Ethereum).
|
|
||||||
|
|
||||||
### Git flow
|
|
||||||
|
|
||||||
To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets this all up and streamlines your work flow.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
Testing one library:
|
|
||||||
|
|
||||||
```
|
|
||||||
go test -v -cpu 4 ./eth
|
|
||||||
```
|
|
||||||
|
|
||||||
Using options `-cpu` (number of cores allowed) and `-v` (logging even if no error) is recommended.
|
|
||||||
|
|
||||||
Testing only some methods:
|
|
||||||
|
|
||||||
```
|
|
||||||
go test -v -cpu 4 ./eth -run TestMethod
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: here all tests with prefix _TestMethod_ will be run, so if you got TestMethod, TestMethod1, then both!
|
|
||||||
|
|
||||||
Running benchmarks, eg.:
|
|
||||||
|
|
||||||
```
|
|
||||||
go test -v -cpu 4 -bench . -run BenchmarkJoin
|
|
||||||
```
|
|
||||||
|
|
||||||
for more see [go test flags](http://golang.org/cmd/go/#hdr-Description_of_testing_flags)
|
|
||||||
|
|
||||||
### Metrics and monitoring
|
|
||||||
|
|
||||||
`geth` can do node behaviour monitoring, aggregation and show performance metric charts.
|
|
||||||
Read about [metrics and monitoring](../doc/Metrics-and-Monitoring)
|
|
||||||
|
|
||||||
### Getting Stack Traces
|
|
||||||
|
|
||||||
If `geth` is started with the `--pprof` option, a debugging HTTP server is made available on port 6060. You can bring up http://localhost:6060/debug/pprof to see the heap, running routines etc. By clicking full goroutine stack dump (clicking http://localhost:6060/debug/pprof/goroutine?debug=2) you can generate trace that is useful for debugging.
|
|
||||||
|
|
||||||
Note that if you run multiple instances of `geth`, this port will only work for the first instance that was launched. If you want to generate stacktraces for these other instances, you need to start them up choosing an alternative pprof port. Make sure you are redirecting stderr to a logfile.
|
|
||||||
|
|
||||||
```
|
|
||||||
geth -port=30300 -verbosity 5 --pprof --pprofport 6060 2>> /tmp/00.glog
|
|
||||||
geth -port=30301 -verbosity 5 --pprof --pprofport 6061 2>> /tmp/01.glog
|
|
||||||
geth -port=30302 -verbosity 5 --pprof --pprofport 6062 2>> /tmp/02.glog
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively if you want to kill the clients (in case they hang or stalled syncing, etc) but have the stacktrace too, you can use the `-QUIT` signal with `kill`:
|
|
||||||
|
|
||||||
```
|
|
||||||
killall -QUIT geth
|
|
||||||
```
|
|
||||||
|
|
||||||
This will dump stack traces for each instance to their respective log file.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Thank you for considering to help out with the source code! We welcome contributions from
|
|
||||||
anyone on the internet, and are grateful for even the smallest of fixes!
|
|
||||||
|
|
||||||
GitHub is used to track issues and contribute code, suggestions, feature requests or
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull
|
|
||||||
request (PR) 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
|
|
||||||
gitter channel](https://gitter.im/ethereum/go-ethereum) 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.
|
|
||||||
|
|
||||||
PRs need to be based on and opened against the `master` branch (unless by explicit
|
|
||||||
agreement, you contribute to a complex feature branch).
|
|
||||||
|
|
||||||
Your PR will be reviewed according to the [Code Review
|
|
||||||
Guidelines](../doc/Code-Review-Guidelines).
|
|
||||||
|
|
||||||
We encourage a PR early approach, meaning you create the PR the earliest even without the
|
|
||||||
fix/feature. This will let core devs and other volunteers know you picked up an issue.
|
|
||||||
These early PRs should indicate 'in progress' status.
|
|
||||||
|
|
||||||
## Dev Tutorials (mostly outdated)
|
|
||||||
|
|
||||||
* [Private networks, local clusters and monitoring](../doc/Setting-up-private-network-or-local-cluster)
|
|
||||||
|
|
||||||
* [P2P 101](../doc/Peer-to-Peer): a tutorial about setting up and creating a p2p server and p2p sub protocol.
|
|
||||||
|
|
||||||
* [How to Whisper](../doc/How-to-Whisper): an introduction to whisper.
|
|
|
@ -1,169 +0,0 @@
|
||||||
---
|
|
||||||
title: Commandline options
|
|
||||||
---
|
|
||||||
```
|
|
||||||
$ geth help
|
|
||||||
NAME:
|
|
||||||
geth - the go-ethereum command line interface
|
|
||||||
|
|
||||||
Copyright 2013-2018 The go-ethereum Authors
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
geth [options] command [command options] [arguments...]
|
|
||||||
|
|
||||||
VERSION:
|
|
||||||
1.8.11-stable
|
|
||||||
|
|
||||||
COMMANDS:
|
|
||||||
account Manage accounts
|
|
||||||
attach Start an interactive JavaScript environment (connect to node)
|
|
||||||
bug opens a window to report a bug on the geth repo
|
|
||||||
console Start an interactive JavaScript environment
|
|
||||||
copydb Create a local chain from a target chaindata folder
|
|
||||||
dump Dump a specific block from storage
|
|
||||||
dumpconfig Show configuration values
|
|
||||||
export Export blockchain into file
|
|
||||||
export-preimages Export the preimage database into an RLP stream
|
|
||||||
import Import a blockchain file
|
|
||||||
import-preimages Import the preimage database from an RLP stream
|
|
||||||
init Bootstrap and initialize a new genesis block
|
|
||||||
js Execute the specified JavaScript files
|
|
||||||
license Display license information
|
|
||||||
makecache Generate ethash verification cache (for testing)
|
|
||||||
makedag Generate ethash mining DAG (for testing)
|
|
||||||
monitor Monitor and visualize node metrics
|
|
||||||
removedb Remove blockchain and state databases
|
|
||||||
version Print version numbers
|
|
||||||
wallet Manage Ethereum presale wallets
|
|
||||||
help, h Shows a list of commands or help for one command
|
|
||||||
|
|
||||||
ETHEREUM OPTIONS:
|
|
||||||
--config value TOML configuration file
|
|
||||||
--datadir "/home/ligi/.ethereum" Data directory for the databases and keystore
|
|
||||||
--keystore Directory for the keystore (default = inside the datadir)
|
|
||||||
--nousb Disables monitoring for and managing USB hardware wallets
|
|
||||||
--networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1)
|
|
||||||
--testnet Ropsten network: pre-configured proof-of-work test network
|
|
||||||
--rinkeby Rinkeby network: pre-configured proof-of-authority test network
|
|
||||||
--syncmode "fast" Blockchain sync mode ("fast", "full", or "light")
|
|
||||||
--gcmode value Blockchain garbage collection mode ("full", "archive") (default: "full")
|
|
||||||
--ethstats value Reporting URL of a ethstats service (nodename:secret@host:port)
|
|
||||||
--identity value Custom node name
|
|
||||||
--lightserv value Maximum percentage of time allowed for serving LES requests (0-90) (default: 0)
|
|
||||||
--lightpeers value Maximum number of LES client peers (default: 100)
|
|
||||||
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
|
||||||
|
|
||||||
DEVELOPER CHAIN OPTIONS:
|
|
||||||
--dev Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
|
|
||||||
--dev.period value Block period to use in developer mode (0 = mine only if transaction pending) (default: 0)
|
|
||||||
|
|
||||||
ETHASH OPTIONS:
|
|
||||||
--ethash.cachedir Directory to store the ethash verification caches (default = inside the datadir)
|
|
||||||
--ethash.cachesinmem value Number of recent ethash caches to keep in memory (16MB each) (default: 2)
|
|
||||||
--ethash.cachesondisk value Number of recent ethash caches to keep on disk (16MB each) (default: 3)
|
|
||||||
--ethash.dagdir "/home/ligi/.ethash" Directory to store the ethash mining DAGs (default = inside home folder)
|
|
||||||
--ethash.dagsinmem value Number of recent ethash mining DAGs to keep in memory (1+GB each) (default: 1)
|
|
||||||
--ethash.dagsondisk value Number of recent ethash mining DAGs to keep on disk (1+GB each) (default: 2)
|
|
||||||
|
|
||||||
TRANSACTION POOL OPTIONS:
|
|
||||||
--txpool.nolocals Disables price exemptions for locally submitted transactions
|
|
||||||
--txpool.journal value Disk journal for local transaction to survive node restarts (default: "transactions.rlp")
|
|
||||||
--txpool.rejournal value Time interval to regenerate the local transaction journal (default: 1h0m0s)
|
|
||||||
--txpool.pricelimit value Minimum gas price limit to enforce for acceptance into the pool (default: 1)
|
|
||||||
--txpool.pricebump value Price bump percentage to replace an already existing transaction (default: 10)
|
|
||||||
--txpool.accountslots value Minimum number of executable transaction slots guaranteed per account (default: 16)
|
|
||||||
--txpool.globalslots value Maximum number of executable transaction slots for all accounts (default: 4096)
|
|
||||||
--txpool.accountqueue value Maximum number of non-executable transaction slots permitted per account (default: 64)
|
|
||||||
--txpool.globalqueue value Maximum number of non-executable transaction slots for all accounts (default: 1024)
|
|
||||||
--txpool.lifetime value Maximum amount of time non-executable transaction are queued (default: 3h0m0s)
|
|
||||||
|
|
||||||
PERFORMANCE TUNING OPTIONS:
|
|
||||||
--cache value Megabytes of memory allocated to internal caching (default: 1024)
|
|
||||||
--cache.database value Percentage of cache memory allowance to use for database io (default: 75)
|
|
||||||
--cache.gc value Percentage of cache memory allowance to use for trie pruning (default: 25)
|
|
||||||
--trie-cache-gens value Number of trie node generations to keep in memory (default: 120)
|
|
||||||
|
|
||||||
ACCOUNT OPTIONS:
|
|
||||||
--unlock value Comma separated list of accounts to unlock
|
|
||||||
--password value Password file to use for non-interactive password input
|
|
||||||
|
|
||||||
API AND CONSOLE OPTIONS:
|
|
||||||
--rpc Enable the HTTP-RPC server
|
|
||||||
--rpcaddr value HTTP-RPC server listening interface (default: "localhost")
|
|
||||||
--rpcport value HTTP-RPC server listening port (default: 8545)
|
|
||||||
--rpcapi value API's offered over the HTTP-RPC interface
|
|
||||||
--ws Enable the WS-RPC server
|
|
||||||
--wsaddr value WS-RPC server listening interface (default: "localhost")
|
|
||||||
--wsport value WS-RPC server listening port (default: 8546)
|
|
||||||
--wsapi value API's offered over the WS-RPC interface
|
|
||||||
--wsorigins value Origins from which to accept websockets requests
|
|
||||||
--ipcdisable Disable the IPC-RPC server
|
|
||||||
--ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it)
|
|
||||||
--rpccorsdomain value Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
|
||||||
--rpcvhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost")
|
|
||||||
--jspath loadScript JavaScript root path for loadScript (default: ".")
|
|
||||||
--exec value Execute JavaScript statement
|
|
||||||
--preload value Comma separated list of JavaScript files to preload into the console
|
|
||||||
|
|
||||||
NETWORKING OPTIONS:
|
|
||||||
--bootnodes value Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)
|
|
||||||
--bootnodesv4 value Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)
|
|
||||||
--bootnodesv5 value Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)
|
|
||||||
--port value Network listening port (default: 30303)
|
|
||||||
--maxpeers value Maximum number of network peers (network disabled if set to 0) (default: 25)
|
|
||||||
--maxpendpeers value Maximum number of pending connection attempts (defaults used if set to 0) (default: 0)
|
|
||||||
--nat value NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>) (default: "any")
|
|
||||||
--nodiscover Disables the peer discovery mechanism (manual peer addition)
|
|
||||||
--v5disc Enables the experimental RLPx V5 (Topic Discovery) mechanism
|
|
||||||
--netrestrict value Restricts network communication to the given IP networks (CIDR masks)
|
|
||||||
--nodekey value P2P node key file
|
|
||||||
--nodekeyhex value P2P node key as hex (for testing)
|
|
||||||
|
|
||||||
MINER OPTIONS:
|
|
||||||
--mine Enable mining
|
|
||||||
--minerthreads value Number of CPU threads to use for mining (default: 8)
|
|
||||||
--etherbase value Public address for block mining rewards (default = first account created) (default: "0")
|
|
||||||
--targetgaslimit value Target gas limit sets the artificial target gas floor for the blocks to mine (default: 4712388)
|
|
||||||
--gasprice "18000000000" Minimal gas price to accept for mining a transactions
|
|
||||||
--extradata value Block extra data set by the miner (default = client version)
|
|
||||||
|
|
||||||
GAS PRICE ORACLE OPTIONS:
|
|
||||||
--gpoblocks value Number of recent blocks to check for gas prices (default: 20)
|
|
||||||
--gpopercentile value Suggested gas price is the given percentile of a set of recent transaction gas prices (default: 60)
|
|
||||||
|
|
||||||
VIRTUAL MACHINE OPTIONS:
|
|
||||||
--vmdebug Record information useful for VM and contract debugging
|
|
||||||
|
|
||||||
LOGGING AND DEBUGGING OPTIONS:
|
|
||||||
--metrics Enable metrics collection and reporting
|
|
||||||
--fakepow Disables proof-of-work verification
|
|
||||||
--nocompaction Disables db compaction after import
|
|
||||||
--verbosity value Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 3)
|
|
||||||
--vmodule value Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)
|
|
||||||
--backtrace value Request a stack trace at a specific logging statement (e.g. "block.go:271")
|
|
||||||
--debug Prepends log messages with call-site location (file and line number)
|
|
||||||
--pprof Enable the pprof HTTP server
|
|
||||||
--pprofaddr value pprof HTTP server listening interface (default: "127.0.0.1")
|
|
||||||
--pprofport value pprof HTTP server listening port (default: 6060)
|
|
||||||
--memprofilerate value Turn on memory profiling with the given rate (default: 524288)
|
|
||||||
--blockprofilerate value Turn on block profiling with the given rate (default: 0)
|
|
||||||
--cpuprofile value Write CPU profile to the given file
|
|
||||||
--trace value Write execution trace to the given file
|
|
||||||
|
|
||||||
WHISPER (EXPERIMENTAL) OPTIONS:
|
|
||||||
--shh Enable Whisper
|
|
||||||
--shh.maxmessagesize value Max message size accepted (default: 1048576)
|
|
||||||
--shh.pow value Minimum POW accepted (default: 0.2)
|
|
||||||
|
|
||||||
DEPRECATED OPTIONS:
|
|
||||||
--fast Enable fast syncing through state downloads (replaced by --syncmode)
|
|
||||||
--light Enable light client mode (replaced by --syncmode)
|
|
||||||
|
|
||||||
MISC OPTIONS:
|
|
||||||
--help, -h show help
|
|
||||||
|
|
||||||
|
|
||||||
COPYRIGHT:
|
|
||||||
Copyright 2013-2018 The go-ethereum Authors
|
|
||||||
|
|
||||||
```
|
|
|
@ -1,77 +0,0 @@
|
||||||
---
|
|
||||||
title: JavaScript console
|
|
||||||
---
|
|
||||||
Ethereum implements a **javascript runtime environment** (JSRE) that can be used in either interactive (console) or non-interactive (script) mode.
|
|
||||||
|
|
||||||
Ethereum's Javascript console exposes the full [web3 JavaScript Dapp API](https://github.com/ethereum/wiki/wiki/JavaScript-API) and the [admin API](JavaScript-Console#javascript-console-api).
|
|
||||||
|
|
||||||
## Interactive use: the JSRE REPL Console
|
|
||||||
|
|
||||||
The `ethereum CLI` executable `geth` has a JavaScript console (a **Read, Evaluate & Print Loop** = REPL exposing the JSRE), which can be started with the `console` or `attach` subcommand. The `console` subcommands starts the geth node and then opens the console. The `attach` subcommand will not start the geth node but instead tries to open the console on a running geth instance.
|
|
||||||
|
|
||||||
$ geth console
|
|
||||||
$ geth attach
|
|
||||||
|
|
||||||
The attach node accepts an endpoint in case the geth node is running with a non default ipc endpoint or you would like to connect over the rpc interface.
|
|
||||||
|
|
||||||
$ geth attach ipc:/some/custom/path
|
|
||||||
$ geth attach http://191.168.1.1:8545
|
|
||||||
$ geth attach ws://191.168.1.1:8546
|
|
||||||
|
|
||||||
Note that by default the geth node doesn't start the http and weboscket service and not all functionality is provided over these interfaces due to security reasons. These defaults can be overridden when the `--rpcapi` and `--wsapi` arguments when the geth node is started, or with [admin.startRPC](Management-APIs#admin_startrpc) and [admin.startWS](Management-APIs#admin_startws).
|
|
||||||
|
|
||||||
If you need log information, start with:
|
|
||||||
|
|
||||||
$ geth --verbosity 5 console 2>> /tmp/eth.log
|
|
||||||
|
|
||||||
Otherwise mute your logs, so that it does not pollute your console:
|
|
||||||
|
|
||||||
$ geth console 2>> /dev/null
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
$ geth --verbosity 0 console
|
|
||||||
|
|
||||||
Geth has support to load custom JavaScript files into the console through the `--preload` argument. This can be used to load often used functions, setup web3 contract objects, or ...
|
|
||||||
```
|
|
||||||
geth --preload "/my/scripts/folder/utils.js,/my/scripts/folder/contracts.js" console
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Non-interactive use: JSRE script mode
|
|
||||||
|
|
||||||
It's also possible to execute files to the JavaScript interpreter. The `console` and `attach` subcommand accept the `--exec` argument which is a javascript statement.
|
|
||||||
|
|
||||||
$ geth --exec "eth.blockNumber" attach
|
|
||||||
|
|
||||||
This prints the current block number of a running geth instance.
|
|
||||||
|
|
||||||
Or execute a local script with more complex statements on a remote node over http:
|
|
||||||
|
|
||||||
$ geth --exec 'loadScript("/tmp/checkbalances.js")' attach http://123.123.123.123:8545
|
|
||||||
$ geth --jspath "/tmp" --exec 'loadScript("checkbalances.js")' attach http://123.123.123.123:8545
|
|
||||||
|
|
||||||
Use the `--jspath <path/to/my/js/root>` to set a libdir for your js scripts. Parameters to `loadScript()` with no absolute path will be understood relative to this directory.
|
|
||||||
|
|
||||||
You can exit the console cleanly by typing `exit` or simply with `CTRL-C`.
|
|
||||||
|
|
||||||
## Caveat
|
|
||||||
|
|
||||||
The go-ethereum JSRE uses the [Otto JS VM](https://github.com/robertkrimen/otto) which has some limitations:
|
|
||||||
|
|
||||||
* "use strict" will parse, but does nothing.
|
|
||||||
* The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification.
|
|
||||||
|
|
||||||
Note that the other known limitation of Otto (namely the lack of timers) is taken care of. Ethereum JSRE implements both `setTimeout` and `setInterval`. In addition to this, the console provides `admin.sleep(seconds)` as well as a "blocktime sleep" method `admin.sleepBlocks(number)`.
|
|
||||||
|
|
||||||
Since `web3.js` uses the [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) library (MIT Expat Licence), it is also autoloded.
|
|
||||||
|
|
||||||
## Timers
|
|
||||||
|
|
||||||
In addition to the full functionality of JS (as per ECMA5), the ethereum JSRE is augmented with various timers. It implements `setInterval`, `clearInterval`, `setTimeout`, `clearTimeout` you may be used to using in browser windows. It also provides implementation for `admin.sleep(seconds)` and a block based timer, `admin.sleepBlocks(n)` which sleeps till the number of new blocks added is equal to or greater than `n`, think "wait for n confirmations".
|
|
||||||
|
|
||||||
# Management APIs
|
|
||||||
|
|
||||||
Beside the official [DApp API](https://github.com/ethereum/wiki/JSON-RPC) interface the go ethereum node has support for additional management API's. These API's are offered using [JSON-RPC](http://www.jsonrpc.org/specification) and follow the same conventions as used in the DApp API. The go ethereum package comes with a console client which has support for all additional API's.
|
|
||||||
|
|
||||||
[The management API has its own wiki page](Management-APIs).
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,49 +0,0 @@
|
||||||
---
|
|
||||||
title: FAQ
|
|
||||||
---
|
|
||||||
***
|
|
||||||
**Q.** I noticed my peercount slowly decrease, and now it is at 0. Restarting doesn't get any peers.
|
|
||||||
|
|
||||||
**A.** Check and sync your clock with ntp. [Example](http://askubuntu.com/questions/254826/how-to-force-a-clock-update-using-ntp) `sudo ntpdate -s time.nist.gov`
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
**Q.** I would like to run multiple geth instances but got the error "Fatal: blockchain db err: resource temporarily unavailable".
|
|
||||||
|
|
||||||
**A.** Geth uses a datadir to store the blockchain, accounts and some additional information. This directory cannot be shared between running instances. If you would like to run multiple instances follow [these](../doc/Setting-up-private-network-or-local-cluster) instructions.
|
|
||||||
|
|
||||||
**Q.** How do Ethereum syncing work?
|
|
||||||
|
|
||||||
**A.** The current default mode of sync for Geth is called fast sync. Instead of starting from the genesis block and reprocessing all the transactions that ever occurred (which could take weeks), fast sync downloads the blocks, and only verifies the associated proof-of-works. Downloading all the blocks is a straightforward and fast procedure and will relatively quickly reassemble the entire chain.
|
|
||||||
|
|
||||||
Many people falsely assume that because they have the blocks, they are in sync. Unfortunately this is not the case, since no transaction was executed, so we do not have any account state available (ie. balances, nonces, smart contract code and data). These need to be downloaded separately and cross checked with the latest blocks. This phase is called the state trie download and it actually runs concurrently with the block downloads; alas it take a lot longer nowadays than downloading the blocks.
|
|
||||||
|
|
||||||
So, what's the state trie? In the Ethereum mainnet, there are a ton of accounts already, which track the balance, nonce, etc of each user/contract. The accounts themselves are however insufficient to run a node, they need to be cryptographically linked to each block so that nodes can actually verify that the account's are not tampered with. This cryptographic linking is done by creating a tree data structure above the accounts, each level aggregating the layer below it into an ever smaller layer, until you reach the single root. This gigantic data structure containing all the accounts and the intermediate cryptographic proofs is called the state trie.
|
|
||||||
|
|
||||||
Ok, so why does this pose a problem? This trie data structure is an intricate interlink of hundreds of millions of tiny cryptographic proofs (trie nodes). To truly have a synchronized node, you need to download all the account data, as well as all the tiny cryptographic proofs to verify that noone in the network is trying to cheat you. This itself is already a crazy number of data items. The part where it gets even messier is that this data is constantly morphing: at every block (15s), about 1000 nodes are deleted from this trie and about 2000 new ones are added. This means your node needs to synchronize a dataset that is changing 200 times per second. The worst part is that while you are synchronizing, the network is moving forward, and state that you begun to download might disappear while you're downloading, so your node needs to constantly follow the network while trying to gather all the recent data. But until you actually do gather all the data, your local node is not usable since it cannot cryptographically prove anything about any accounts.
|
|
||||||
|
|
||||||
If you see that you are 64 blocks behind mainnet, you aren't yet synchronized, not even close. You are just done with the block download phase and still running the state downloads. You can see this yourself via the seemingly endless Imported state entries [...] stream of logs. You'll need to wait that out too before your node comes truly online.
|
|
||||||
|
|
||||||
**Q: The node just hangs on importing state enties?!**
|
|
||||||
|
|
||||||
**A**: The node doesn't hang, it just doesn't know how large the state trie is in advance so it keeps on going and going and going until it discovers and downloads the entire thing.
|
|
||||||
|
|
||||||
The reason is that a block in Ethereum only contains the state root, a single hash of the root node. When the node begins synchronizing, it knows about exactly 1 node and tries to download it. That node, can refer up to 16 new nodes, so in the next step, we'll know about 16 new nodes and try to download those. As we go along the download, most of the nodes will reference new ones that we didn't know about until then. This is why you might be tempted to think it's stuck on the same numbers. It is not, rather it's discovering and downloading the trie as it goes along.
|
|
||||||
|
|
||||||
**Q: I'm stuck at 64 blocks behind mainnet?!**
|
|
||||||
|
|
||||||
*A:* As explained above, you are not stuck, just finished with the block download phase, waiting for the state download phase to complete too. This latter phase nowadays take a lot longer than just getting the blocks.
|
|
||||||
|
|
||||||
**Q: Why does downloading the state take so long, I have good bandwidth?**
|
|
||||||
|
|
||||||
**A:** State sync is mostly limited by disk IO, not bandwidth.
|
|
||||||
|
|
||||||
The state trie in Ethereum contains hundreds of millions of nodes, most of which take the form of a single hash referencing up to 16 other hashes. This is a horrible way to store data on a disk, because there's almost no structure in it, just random numbers referencing even more random numbers. This makes any underlying database weep, as it cannot optimize storing and looking up the data in any meaningful way.
|
|
||||||
|
|
||||||
Not only is storing the data very suboptimal, but due to the 200 modification / second and pruning of past data, we cannot even download it is a properly pre-processed way to make it import faster without the underlying database shuffling it around too much. The end result is that even a fast sync nowadays incurs a huge disk IO cost, which is too much for a mechanical hard drive.
|
|
||||||
|
|
||||||
**Q: Wait, so I can't run a full node on an HDD?**
|
|
||||||
|
|
||||||
**A:** Unfortunately not. Doing a fast sync on an HDD will take more time than you're willing to wait with the current data schema. Even if you do wait it out, an HDD will not be able to keep up with the read/write requirements of transaction processing on mainnet.
|
|
||||||
|
|
||||||
You however should be able to run a light client on an HDD with minimal impact on system resources. If you wish to run a full node however, an SSD is your only option.
|
|
|
@ -1,54 +0,0 @@
|
||||||
---
|
|
||||||
title: Issue handling workflow
|
|
||||||
---
|
|
||||||
### (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 `<category>:<label>` or if need be `<category>:<main>/<sub>`, for example `area: plugins/foobuzzer`.
|
|
||||||
|
|
||||||
Use the following labels. Areas and statuses depend on the application and workflow.
|
|
||||||
- area
|
|
||||||
- `area: android`
|
|
||||||
- `area: clef`
|
|
||||||
- `area: network`
|
|
||||||
- `area: swarm`
|
|
||||||
- `area: whisper`
|
|
||||||
- type
|
|
||||||
- `type: bug`
|
|
||||||
- `type: feature`
|
|
||||||
- `type: documentation`
|
|
||||||
- `type: discussion`
|
|
||||||
- status
|
|
||||||
- `status: PR review`
|
|
||||||
- `status: community working on it`
|
|
||||||
- need
|
|
||||||
- `need: more info`
|
|
||||||
- `need: steps to reproduce`
|
|
||||||
- `need: investigation`
|
|
||||||
- `need: decision`
|
|
||||||
|
|
||||||
Use these milestones
|
|
||||||
- [Future](https://github.com/ethereum/go-ethereum/milestone/80) - Maybe implement one day
|
|
||||||
- [Coming soon](https://github.com/ethereum/go-ethereum/milestone/81) - Not assigned to a specific release, but to be delivered in one of the upcoming releases
|
|
||||||
- \<next version\> - Next release with a version number
|
|
||||||
- \<next-next version\> - The version after the next release with a version number
|
|
||||||
- \<next major release\> - Optional.
|
|
||||||
|
|
||||||
It's ok to not set a due date for a milestone, but once you release it, close it. If you have a few issues dangling, consider moving them to the next milestone, and close this one.
|
|
||||||
|
|
||||||
Optionally, use a project board to collect issues of a larger effort that has an end state and overarches multiple releases.
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
We have a weekly or bi-weekly triage meeting. Issues are preselected by [labelling them "status:triage" and sorted the oldest ones first](https://github.com/ethereum/go-ethereum/issues?q=is%3Aopen+is%3Aissue+label%3Astatus%3Atriage+sort%3Acreated-asc). This is when we go through the new issues and do one of the following
|
|
||||||
1. Close it.
|
|
||||||
1. Assign it to "Coming soon" milestone which doesn't have an end date.
|
|
||||||
1. Move it to the "Future" milestone.
|
|
||||||
1. Change its status to "Need:\<what-is-needed\>".
|
|
||||||
|
|
||||||
Optional further activities:
|
|
||||||
* Label the issue with the appropriate area/component.
|
|
||||||
* Add a section to the FAQ or add a wiki page. Link to it from the issue.
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
title: Documentation
|
|
||||||
---
|
|
||||||
* User documentation can be found at our [Ethereum User Guide and reference manual](http://ethereum.gitbooks.io/frontier-guide/content/).
|
|
||||||
* For the API reference and developer documentation head over to the auto generated [GoDoc](https://godoc.org/github.com/ethereum/go-ethereum) documentation.
|
|
||||||
|
|
||||||
This is the documentation for the official Ethereum golang implementation. For generic Ethereum-related information (whitepaper, yellow paper, protocol and interface specs, APIs, DAPP development guides, etc) see the [Ethereum main wiki](https://github.com/ethereum/wiki/wiki).
|
|
||||||
|
|
||||||
Main entry points:
|
|
||||||
|
|
||||||
* [Installation Instructions](../install-and-build/Building-Ethereum)
|
|
||||||
* [Management APIs](../interface/Management-APIs)
|
|
||||||
* [Managing Accounts](../how-to/Managing-your-accounts)
|
|
||||||
* [Command Line Options](../interface/Command-Line-Options)
|
|
||||||
* [JavaScript Console](../interface/JavaScript-Console)
|
|
||||||
* [Private Network](../doc/Private-network)
|
|
||||||
* [Developers' Guide](../install-and-build/Developers-Guide)
|
|
||||||
* [Whisper v6](../doc/Whisper)
|
|
||||||
|
|
||||||
Sidebar lists all pages.
|
|
|
@ -1,13 +1,52 @@
|
||||||
---
|
<!DOCTYPE html>
|
||||||
layout: default
|
<html lang="en">
|
||||||
title: Downloads
|
<head>
|
||||||
root: ..
|
<meta charset="utf-8">
|
||||||
permalink: /downloads/
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
css:
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
- /static/styles/custom/downloads.css
|
|
||||||
js:
|
<title>Go Ethereum Downloads</title>
|
||||||
- /static/scripts/filesize.min.js
|
<link rel="icon" type="image/png" href="../static/images/favicon.png" />
|
||||||
---
|
|
||||||
|
<link href="../static/styles/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link href="../static/styles/flatly.min.css" rel="stylesheet" />
|
||||||
|
<link href="../static/styles/font-awesome.min.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link href="../static/styles/custom/common.css" rel="stylesheet" />
|
||||||
|
<link href="../static/styles/custom/downloads.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<script src="../static/scripts/jquery.min.js"></script>
|
||||||
|
<script src="../static/scripts/bootstrap.min.js"></script>
|
||||||
|
<script src="../static/scripts/moment.min.js"></script>
|
||||||
|
<script src="../static/scripts/marked.min.js"></script>
|
||||||
|
<script src="../static/scripts/emojify.min.js"></script>
|
||||||
|
<script src="../static/scripts/filesize.min.js"></script>
|
||||||
|
|
||||||
|
<script src="../static/scripts/custom/polyfills.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-default navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="../">Go Ethereum</a>
|
||||||
|
</div>
|
||||||
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a href="../install/">Install</a></li>
|
||||||
|
<li class="active"><a href="../downloads/">Downloads</a></li>
|
||||||
|
<!--<li><a href="../guide/">Guide</a></li>-->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div id="loader" class="modal fade" role="dialog" data-backdrop="static" data-keyboard="false">
|
<div id="loader" class="modal fade" role="dialog" data-backdrop="static" data-keyboard="false">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
@ -215,6 +254,11 @@ js:
|
||||||
<p>Note that you must use the name of the signature file, and you should use the one that's appropriate to the download you're verifying.</p>
|
<p>Note that you must use the name of the signature file, and you should use the one that's appropriate to the download you're verifying.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<footer>
|
||||||
|
<p>© 2013-2016. The go-ethereum Authors.</p>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -546,3 +590,5 @@ js:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
59
index.html
59
index.html
|
@ -1,8 +1,51 @@
|
||||||
---
|
<!DOCTYPE html>
|
||||||
layout: default
|
<html lang="en">
|
||||||
css:
|
<head>
|
||||||
- /static/styles/custom/home.css
|
<meta charset="utf-8">
|
||||||
---
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>Go Ethereum</title>
|
||||||
|
<link rel="icon" type="image/png" href="./static/images/favicon.png" />
|
||||||
|
|
||||||
|
<link href="./static/styles/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link href="./static/styles/flatly.min.css" rel="stylesheet" />
|
||||||
|
<link href="./static/styles/font-awesome.min.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link href="./static/styles/custom/common.css" rel="stylesheet" />
|
||||||
|
<link href="./static/styles/custom/home.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<script src="./static/scripts/jquery.min.js"></script>
|
||||||
|
<script src="./static/scripts/bootstrap.min.js"></script>
|
||||||
|
<script src="./static/scripts/moment.min.js"></script>
|
||||||
|
<script src="./static/scripts/marked.min.js"></script>
|
||||||
|
<script src="./static/scripts/emojify.min.js"></script>
|
||||||
|
|
||||||
|
<script src="../static/scripts/custom/polyfills.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-default navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="#">Go Ethereum</a>
|
||||||
|
</div>
|
||||||
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a href="install/">Install</a></li>
|
||||||
|
<li><a href="downloads/">Downloads</a></li>
|
||||||
|
<!--<li><a href="/guide/">Guide</a></li>-->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<div class="container mascot">
|
<div class="container mascot">
|
||||||
<h1>Go Ethereum</h1>
|
<h1>Go Ethereum</h1>
|
||||||
|
@ -47,4 +90,10 @@ css:
|
||||||
<p class="lead">See our <a href="./install">installation guide</a> or our <a href="https://github.com/ethereum/go-ethereum/wiki" target="_blank">wiki pages</a> for details!</p>
|
<p class="lead">See our <a href="./install">installation guide</a> or our <a href="https://github.com/ethereum/go-ethereum/wiki" target="_blank">wiki pages</a> for details!</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<footer>
|
||||||
|
<p>© 2013-2016. The go-ethereum Authors.</p>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
See [Installing Geth](doc/Installing-Geth).
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<title>Go Ethereum Installation</title>
|
||||||
|
<link rel="icon" type="image/png" href="../static/images/favicon.png" />
|
||||||
|
|
||||||
|
<link href="../static/styles/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link href="../static/styles/flatly.min.css" rel="stylesheet" />
|
||||||
|
<link href="../static/styles/font-awesome.min.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link href="../static/styles/custom/common.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<script src="../static/scripts/jquery.min.js"></script>
|
||||||
|
<script src="../static/scripts/bootstrap.min.js"></script>
|
||||||
|
<script src="../static/scripts/moment.min.js"></script>
|
||||||
|
<script src="../static/scripts/marked.min.js"></script>
|
||||||
|
<script src="../static/scripts/emojify.min.js"></script>
|
||||||
|
|
||||||
|
<script src="../static/scripts/custom/polyfills.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-default navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a class="navbar-brand" href="../">Go Ethereum</a>
|
||||||
|
</div>
|
||||||
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="active"><a href="../install/">Install</a></li>
|
||||||
|
<li><a href="../downloads/">Downloads</a></li>
|
||||||
|
<!--<li><a href="../guide/">Guide</a></li>-->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container" style="padding-top: 24px;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h1>Installing Go Ethereum</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12" id="content"></div>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<footer>
|
||||||
|
<p>© 2013-2016. The go-ethereum Authors.</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$.ajax({
|
||||||
|
url: 'https://raw.githubusercontent.com/wiki/ethereum/go-ethereum/Installing-Geth.md',
|
||||||
|
error: function() {
|
||||||
|
alert("Failed to load latest release!");
|
||||||
|
},
|
||||||
|
dataType: 'text',
|
||||||
|
success: function(data) {
|
||||||
|
$('#content').html(marked(data));
|
||||||
|
emojify.setConfig({img_dir: '../static/images/emoji'});
|
||||||
|
emojify.run(document.getElementById('content'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue