mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
signer: add ipc capability+review concerns
This commit is contained in:
parent
3096761623
commit
895199d9f8
14 changed files with 180 additions and 37 deletions
|
|
@ -89,6 +89,15 @@ invoking methods with the following info:
|
||||||
* [x] Address of API (http/ipc)
|
* [x] Address of API (http/ipc)
|
||||||
* [ ] List of known accounts
|
* [ ] List of known accounts
|
||||||
|
|
||||||
|
* [ ] `account_signRawTransaction`
|
||||||
|
* [ ] `account_bulkSignTransactions([] transactions)` should
|
||||||
|
* only exist if enabled via config/flag
|
||||||
|
* only allow non-data-sending transactions
|
||||||
|
* all txs must use the same `from`-account
|
||||||
|
* let the user confirm, showing
|
||||||
|
* the total amount
|
||||||
|
* the number of unique recipients
|
||||||
|
|
||||||
|
|
||||||
* Geth todos
|
* Geth todos
|
||||||
- The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is
|
- The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is
|
||||||
|
|
@ -115,7 +124,7 @@ put together is a bit of a hack into the http server. This could probably be gre
|
||||||
|
|
||||||
### External API
|
### External API
|
||||||
|
|
||||||
The signer listens to HTTP requests on `rpcaddr`:`rpcport`. The messages are
|
The signer listens to HTTP requests on `rpcaddr`:`rpcport`, with the same JSONRPC standard as Geth. The messages are
|
||||||
expected to be JSON [jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
|
expected to be JSON [jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
|
||||||
|
|
||||||
Some of these call can require user interaction. Clients must be aware that responses
|
Some of these call can require user interaction. Clients must be aware that responses
|
||||||
|
|
@ -172,7 +181,7 @@ None
|
||||||
- url [string]: location of the keyfile
|
- url [string]: location of the keyfile
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -206,7 +215,7 @@ None
|
||||||
- account.url [string]: location of the account
|
- account.url [string]: location of the account
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -253,7 +262,7 @@ None
|
||||||
- signed transaction in RLP encoded form [data]
|
- signed transaction in RLP encoded form [data]
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -270,7 +279,10 @@ None
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": 67,
|
"id": 67,
|
||||||
|
|
@ -283,7 +295,7 @@ None
|
||||||
#### Sample call with ABI-data
|
#### Sample call with ABI-data
|
||||||
|
|
||||||
|
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "account_signTransaction",
|
"method": "account_signTransaction",
|
||||||
|
|
@ -301,7 +313,10 @@ None
|
||||||
],
|
],
|
||||||
"id": 67
|
"id": 67
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"id": 67,
|
"id": 67,
|
||||||
|
|
@ -344,7 +359,7 @@ Bash example:
|
||||||
- calculated signature [data]
|
- calculated signature [data]
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -354,7 +369,10 @@ Bash example:
|
||||||
"0xaabbccdd"
|
"0xaabbccdd"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -375,7 +393,7 @@ Bash example:
|
||||||
- derived account [address]
|
- derived account [address]
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -385,7 +403,10 @@ Bash example:
|
||||||
"0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
|
"0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -410,7 +431,7 @@ Bash example:
|
||||||
- key.url [string]: key URL
|
- key.url [string]: key URL
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -439,6 +460,10 @@ Bash example:
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -464,7 +489,7 @@ Bash example:
|
||||||
more information
|
more information
|
||||||
|
|
||||||
#### Sample call
|
#### Sample call
|
||||||
```
|
```json
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -473,6 +498,10 @@ Bash example:
|
||||||
"0xc7412fc59930fd90099c917a50e5f11d0934b2f5"
|
"0xc7412fc59930fd90099c917a50e5f11d0934b2f5"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
Response
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|
@ -506,7 +535,6 @@ Bash example:
|
||||||
|
|
||||||
These methods needs to be implemented by a UI listener.
|
These methods needs to be implemented by a UI listener.
|
||||||
|
|
||||||
|
|
||||||
By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
|
By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
|
||||||
denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
|
denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
|
||||||
See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
|
See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
|
||||||
|
|
@ -515,6 +543,10 @@ All methods in this API uses object-based parameters, so that there can be no mi
|
||||||
|
|
||||||
See the [ui api changelog](intapi_changelog.md) for information about changes to this API.
|
See the [ui api changelog](intapi_changelog.md) for information about changes to this API.
|
||||||
|
|
||||||
|
OBS! A slight deviation from `json` standard is in place: every request and response should be confined to a single line.
|
||||||
|
Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make
|
||||||
|
things simpler for both parties.
|
||||||
|
|
||||||
### ApproveTx
|
### ApproveTx
|
||||||
|
|
||||||
Invoked when there's a transaction for approval.
|
Invoked when there's a transaction for approval.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,19 @@
|
||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommandlineUI struct {
|
type CommandlineUI struct {
|
||||||
|
|
@ -233,7 +234,8 @@ func (ui *CommandlineUI) ShowInfo(message string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||||
fmt.Printf("Transaction signed: %v", tx.Tx.String())
|
fmt.Printf("Transaction signed:\n ")
|
||||||
|
spew.Dump(tx.Tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) {
|
func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -45,6 +44,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
"os/signal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EXT_API_VERSION -- see extapi_changelog.md
|
// EXT_API_VERSION -- see extapi_changelog.md
|
||||||
|
|
@ -180,6 +180,9 @@ func init() {
|
||||||
utils.NoUSBFlag,
|
utils.NoUSBFlag,
|
||||||
utils.RPCListenAddrFlag,
|
utils.RPCListenAddrFlag,
|
||||||
utils.RPCVirtualHostsFlag,
|
utils.RPCVirtualHostsFlag,
|
||||||
|
utils.IPCDisabledFlag,
|
||||||
|
utils.IPCPathFlag,
|
||||||
|
utils.RPCEnabledFlag,
|
||||||
rpcPortFlag,
|
rpcPortFlag,
|
||||||
signerSecretFlag,
|
signerSecretFlag,
|
||||||
dBFlag,
|
dBFlag,
|
||||||
|
|
@ -330,8 +333,6 @@ func signer(c *cli.Context) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
api core.ExternalAPI
|
api core.ExternalAPI
|
||||||
listener net.Listener
|
|
||||||
server = rpc.NewServer()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
configDir := c.String(configdirFlag.Name)
|
configDir := c.String(configdirFlag.Name)
|
||||||
|
|
@ -396,18 +397,56 @@ func signer(c *cli.Context) error {
|
||||||
log.Info("Audit logs configured", "file", logfile)
|
log.Info("Audit logs configured", "file", logfile)
|
||||||
}
|
}
|
||||||
// register signer API with server
|
// register signer API with server
|
||||||
if err = server.RegisterName("account", api); err != nil {
|
var (
|
||||||
utils.Fatalf("Could not register signer API: %v", err)
|
extapiUrl = "n/a"
|
||||||
|
ipcApiUrl = "n/a"
|
||||||
|
)
|
||||||
|
rpcApi := []rpc.API{
|
||||||
|
rpc.API{
|
||||||
|
Namespace: "account",
|
||||||
|
Public: true,
|
||||||
|
Service: api,
|
||||||
|
Version: "1.0"},
|
||||||
}
|
}
|
||||||
|
if c.Bool(utils.RPCEnabledFlag.Name) {
|
||||||
|
|
||||||
|
vhosts := splitAndTrim(c.GlobalString(utils.RPCVirtualHostsFlag.Name))
|
||||||
|
//!TODO
|
||||||
|
cors := []string{"*"}
|
||||||
|
|
||||||
// start http server
|
// start http server
|
||||||
endpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
|
httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
|
||||||
if listener, err = net.Listen("tcp", endpoint); err != nil {
|
listener, _, err := node.StartHttpEndpoint(httpEndpoint, rpcApi, []string{"account"}, cors, vhosts)
|
||||||
utils.Fatalf("Could not start http listener: %v", err)
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not start RPC api: %v", err)
|
||||||
|
}
|
||||||
|
extapiUrl = fmt.Sprintf("http://%s", httpEndpoint)
|
||||||
|
log.Info("HTTP endpoint opened", "url", extapiUrl)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
listener.Close()
|
||||||
|
log.Info("HTTP endpoint closed", "url", httpEndpoint)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
if !c.Bool(utils.IPCDisabledFlag.Name) {
|
||||||
|
if c.IsSet(utils.IPCPathFlag.Name) {
|
||||||
|
ipcApiUrl = c.String(utils.IPCPathFlag.Name)
|
||||||
|
} else {
|
||||||
|
ipcApiUrl = fmt.Sprintf("%s", filepath.Join(configDir, "signer.ipc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, _, err := node.StartIPCEndpoint(func() bool { return true }, ipcApiUrl, rpcApi)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not start IPC api: %v", err)
|
||||||
|
}
|
||||||
|
log.Info("IPC endpoint opened", "url", ipcApiUrl)
|
||||||
|
defer func() {
|
||||||
|
listener.Close()
|
||||||
|
log.Info("IPC endpoint closed", "url", ipcApiUrl)
|
||||||
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
extapi_url := fmt.Sprintf("http://%s", endpoint)
|
|
||||||
log.Info("HTTP endpoint opened", "url", extapi_url)
|
|
||||||
cors := []string{"*"}
|
|
||||||
|
|
||||||
if c.Bool(testFlag.Name) {
|
if c.Bool(testFlag.Name) {
|
||||||
log.Info("Performing UI test")
|
log.Info("Performing UI test")
|
||||||
|
|
@ -417,12 +456,18 @@ func signer(c *cli.Context) error {
|
||||||
Info: map[string]interface{}{
|
Info: map[string]interface{}{
|
||||||
"extapi_version": EXT_API_VERSION,
|
"extapi_version": EXT_API_VERSION,
|
||||||
"intapi_version": INT_API_VERSION,
|
"intapi_version": INT_API_VERSION,
|
||||||
"extapi_http": extapi_url,
|
"extapi_http": extapiUrl,
|
||||||
"extapi_ipc": nil,
|
"extapi_ipc": ipcApiUrl,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
vhosts := splitAndTrim(c.GlobalString(utils.RPCVirtualHostsFlag.Name))
|
|
||||||
rpc.NewHTTPServer(cors, vhosts, server).Serve(listener)
|
abortChan := make(chan os.Signal)
|
||||||
|
signal.Notify(abortChan, os.Interrupt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case sig := <-abortChan:
|
||||||
|
log.Info("Exiting...", "signal", sig)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
// Copyright 2018 The go-ethereum Authors
|
||||||
// This file is part of go-ethereum.
|
// This file is part of go-ethereum.
|
||||||
//
|
//
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,19 @@
|
||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,19 @@
|
||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,19 @@
|
||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue