mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
signer: fix golint errors (#16653)
* signer/*: golint fixes Specifically naming and comment formatting for documentation * signer/*: fixed naming error crashing build * signer/*: corrected error * signer/core: fix tiny error whitespace * signer/rules: fix test refactor Former-commit-id: e5aa4376db0bb59d577d0fc62b0d5e5766ce445e [formerly 8161f1ac395ffd49126597cb640ca9fff5e3a8df] Former-commit-id: 4b759f413a22175b9bd0b6d47a9878a3e5440b17
This commit is contained in:
@@ -108,9 +108,8 @@ func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) er
|
||||
func (ks keyStorePassphrase) JoinPath(filename string) string {
|
||||
if filepath.IsAbs(filename) {
|
||||
return filename
|
||||
} else {
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
|
||||
// EncryptKey encrypts a key using the specified scrypt parameters into a json
|
||||
|
||||
@@ -56,7 +56,6 @@ func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
|
||||
func (ks keyStorePlain) JoinPath(filename string) string {
|
||||
if filepath.IsAbs(filename) {
|
||||
return filename
|
||||
} else {
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
|
||||
@@ -731,7 +731,7 @@ func doAndroidArchive(cmdline []string) {
|
||||
// Build the Android archive and Maven resources
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
|
||||
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
|
||||
build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
|
||||
|
||||
if *local {
|
||||
// If we're building locally, copy bundle to build dir and skip Maven
|
||||
@@ -852,7 +852,7 @@ func doXCodeFramework(cmdline []string) {
|
||||
// Build the iOS XCode framework
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
|
||||
build.MustRun(gomobileTool("init"))
|
||||
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
|
||||
if *local {
|
||||
// If we're building locally, use the build folder and stop afterwards
|
||||
|
||||
@@ -12,6 +12,11 @@ synchronised with the chain or a particular Ethereum node that has no built-in (
|
||||
Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory),
|
||||
or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup.
|
||||
|
||||
Check out
|
||||
|
||||
* the [tutorial](tutorial.md) for some concrete examples on how the signer works.
|
||||
* the [setup docs](docs/setup.md) for some information on how to configure it to work on QubesOS or USBArmory.
|
||||
|
||||
|
||||
## Command line flags
|
||||
Clef accepts the following command line options:
|
||||
@@ -49,7 +54,6 @@ Example:
|
||||
signer -keystore /my/keystore -chainid 4
|
||||
```
|
||||
|
||||
Check out the [tutorial](tutorial.md) for some concrete examples on how the signer works.
|
||||
|
||||
## Security model
|
||||
|
||||
@@ -862,3 +866,12 @@ A UI should conform to the following rules.
|
||||
along with the UI.
|
||||
|
||||
|
||||
### UI Implementations
|
||||
|
||||
There are a couple of implementation for a UI. We'll try to keep this list up to date.
|
||||
|
||||
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
|
||||
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
|
||||
| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
|
||||
| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
|
||||
| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
|
||||
|
||||
BIN
cmd/clef/docs/qubes/clef_qubes_http.png
Normal file
BIN
cmd/clef/docs/qubes/clef_qubes_http.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
cmd/clef/docs/qubes/clef_qubes_qrexec.png
Normal file
BIN
cmd/clef/docs/qubes/clef_qubes_qrexec.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
cmd/clef/docs/qubes/qrexec-example.png
Normal file
BIN
cmd/clef/docs/qubes/qrexec-example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
23
cmd/clef/docs/qubes/qubes-client.py
Normal file
23
cmd/clef/docs/qubes/qubes-client.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
This implements a dispatcher which listens to localhost:8550, and proxies
|
||||
requests via qrexec to the service qubes.EthSign on a target domain
|
||||
"""
|
||||
|
||||
import http.server
|
||||
import socketserver,subprocess
|
||||
|
||||
PORT=8550
|
||||
TARGET_DOMAIN= 'debian-work'
|
||||
|
||||
class Dispatcher(http.server.BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
post_data = self.rfile.read(int(self.headers['Content-Length']))
|
||||
p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
output = p.communicate(post_data)[0]
|
||||
self.wfile.write(output)
|
||||
|
||||
|
||||
with socketserver.TCPServer(("",PORT), Dispatcher) as httpd:
|
||||
print("Serving at port", PORT)
|
||||
httpd.serve_forever()
|
||||
|
||||
16
cmd/clef/docs/qubes/qubes.Clefsign
Normal file
16
cmd/clef/docs/qubes/qubes.Clefsign
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
SIGNER_BIN="/home/user/tools/clef/clef"
|
||||
SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN"
|
||||
|
||||
# Start clef if not already started
|
||||
if [ ! -S /home/user/.clef/clef.ipc ]; then
|
||||
$SIGNER_CMD &
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Should be started by now
|
||||
if [ -S /home/user/.clef/clef.ipc ]; then
|
||||
# Post incoming request to HTTP channel
|
||||
curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null
|
||||
fi
|
||||
BIN
cmd/clef/docs/qubes/qubes_newaccount-1.png
Normal file
BIN
cmd/clef/docs/qubes/qubes_newaccount-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
cmd/clef/docs/qubes/qubes_newaccount-2.png
Normal file
BIN
cmd/clef/docs/qubes/qubes_newaccount-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
198
cmd/clef/docs/setup.md
Normal file
198
cmd/clef/docs/setup.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Setting up Clef
|
||||
|
||||
This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop,
|
||||
in order to ensure that the keys remain safe in the event that your computer should get compromised.
|
||||
|
||||
## Qubes OS
|
||||
|
||||
|
||||
### Background
|
||||
|
||||
The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for
|
||||
different purposes such as:
|
||||
|
||||
- personal
|
||||
- Your personal email, browsing etc
|
||||
- work
|
||||
- Work email etc
|
||||
- vault
|
||||
- a VM without network access, where gpg-keys and/or keepass credentials are stored.
|
||||
|
||||
A couple of dedicated virtual machines handle externalities:
|
||||
|
||||
- sys-net provides networking to all other (network-enabled) machines
|
||||
- sys-firewall handles firewall rules
|
||||
- sys-usb handles USB devices, and can map usb-devices to certain qubes.
|
||||
|
||||
The goal of this document is to describe how we can set up clef to provide secure transaction
|
||||
signing from a `vault` vm, to another networked qube which runs Dapps.
|
||||
|
||||
### Setup
|
||||
|
||||
There are two ways that this can be achieved: integrated via Qubes or integrated via networking.
|
||||
|
||||
|
||||
#### 1. Qubes Integrated
|
||||
|
||||
Qubes provdes a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request
|
||||
to another qube. The OS then asks the user if the call is permitted.
|
||||
|
||||

|
||||
|
||||
A policy-file can be created to allow such interaction. On the `target` domain, a service is invoked which can read the
|
||||
`stdin` from the `client` qube.
|
||||
|
||||
This is how [Split GPG](https://www.qubes-os.org/doc/split-gpg/) is implemented. We can set up Clef the same way:
|
||||
|
||||
##### Server
|
||||
|
||||

|
||||
|
||||
On the `target` qubes, we need to define the rpc service.
|
||||
|
||||
[qubes.Clefsign](qubes/qubes.Clefsign):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
SIGNER_BIN="/home/user/tools/clef/clef"
|
||||
SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN"
|
||||
|
||||
# Start clef if not already started
|
||||
if [ ! -S /home/user/.clef/clef.ipc ]; then
|
||||
$SIGNER_CMD &
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Should be started by now
|
||||
if [ -S /home/user/.clef/clef.ipc ]; then
|
||||
# Post incoming request to HTTP channel
|
||||
curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null
|
||||
fi
|
||||
|
||||
```
|
||||
This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept.
|
||||
It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel.
|
||||
|
||||
It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc`
|
||||
socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request
|
||||
data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers.
|
||||
|
||||
To enable the service:
|
||||
|
||||
``` bash
|
||||
sudo cp qubes.Clefsign /etc/qubes-rpc/
|
||||
sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign
|
||||
```
|
||||
|
||||
This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well
|
||||
with minimal requirements.
|
||||
|
||||
##### Client
|
||||
|
||||
|
||||
On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it.
|
||||
|
||||
|
||||
[qubes-client.py](qubes/client/qubes-client.py):
|
||||
|
||||
```python
|
||||
|
||||
"""
|
||||
This implements a dispatcher which listens to localhost:8550, and proxies
|
||||
requests via qrexec to the service qubes.EthSign on a target domain
|
||||
"""
|
||||
|
||||
import http.server
|
||||
import socketserver,subprocess
|
||||
|
||||
PORT=8550
|
||||
TARGET_DOMAIN= 'debian-work'
|
||||
|
||||
class Dispatcher(http.server.BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
post_data = self.rfile.read(int(self.headers['Content-Length']))
|
||||
p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
output = p.communicate(post_data)[0]
|
||||
self.wfile.write(output)
|
||||
|
||||
|
||||
with socketserver.TCPServer(("",PORT), Dispatcher) as httpd:
|
||||
print("Serving at port", PORT)
|
||||
httpd.serve_forever()
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### Testing
|
||||
|
||||
To test the flow, if we have set up `debian-work` as the `target`, we can do
|
||||
|
||||
```bash
|
||||
$ cat newaccnt.json
|
||||
{ "id": 0, "jsonrpc": "2.0","method": "account_new","params": []}
|
||||
|
||||
$ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign
|
||||
```
|
||||
|
||||
This should pop up first a dialog to allow the IPC call:
|
||||
|
||||

|
||||
|
||||
Followed by a GTK-dialog to approve the operation
|
||||
|
||||

|
||||
|
||||
To test the full flow, we use the client wrapper. Start it on the `client` qube:
|
||||
```
|
||||
[user@work qubes]$ python3 qubes-client.py
|
||||
```
|
||||
|
||||
Make the request over http (`client` qube):
|
||||
```
|
||||
[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550
|
||||
```
|
||||
And it should show the same popups again.
|
||||
|
||||
##### Pros and cons
|
||||
|
||||
The benefits of this setup are:
|
||||
|
||||
- This is the qubes-os intended model for inter-qube communication,
|
||||
- and thus benefits from qubes-os dialogs and policies for user approval
|
||||
|
||||
However, it comes with a couple of drawbacks:
|
||||
|
||||
- The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy
|
||||
will either drop important headers, or replace them.
|
||||
- The `Host` header is most likely `localhost`
|
||||
- The `Origin` header must be forwarded
|
||||
- Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header,
|
||||
since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address.
|
||||
- Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups:
|
||||
- One qubes-specific where the user specifies the `target` vm
|
||||
- One clef-specific to approve the transaction
|
||||
|
||||
|
||||
#### 2. Network integrated
|
||||
|
||||
The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible
|
||||
form other qubes.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## USBArmory
|
||||
|
||||
The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size
|
||||
computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network
|
||||
to your computer. Over this new network interface, you can SSH into the device.
|
||||
|
||||
Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only
|
||||
ever connects to a local network between your computer and the device itself.
|
||||
|
||||
Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access
|
||||
to the USB Armory would trivially be able to extract the contents of the device filesystem.
|
||||
|
||||
@@ -21,12 +21,12 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
||||
goruntime "runtime"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -86,6 +86,7 @@ func runCmd(ctx *cli.Context) error {
|
||||
chainConfig *params.ChainConfig
|
||||
sender = common.BytesToAddress([]byte("sender"))
|
||||
receiver = common.BytesToAddress([]byte("receiver"))
|
||||
blockNumber uint64
|
||||
)
|
||||
if ctx.GlobalBool(MachineFlag.Name) {
|
||||
tracer = NewJSONLogger(logconfig, os.Stdout)
|
||||
@@ -101,6 +102,7 @@ func runCmd(ctx *cli.Context) error {
|
||||
genesis := gen.ToBlock(db)
|
||||
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
||||
chainConfig = gen.Config
|
||||
blockNumber = gen.Number
|
||||
} else {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
|
||||
@@ -156,11 +158,12 @@ func runCmd(ctx *cli.Context) error {
|
||||
|
||||
initialGas := ctx.GlobalUint64(GasFlag.Name)
|
||||
runtimeConfig := runtime.Config{
|
||||
Origin: sender,
|
||||
State: statedb,
|
||||
GasLimit: initialGas,
|
||||
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
||||
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
||||
Origin: sender,
|
||||
State: statedb,
|
||||
GasLimit: initialGas,
|
||||
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
||||
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
||||
BlockNumber: new(big.Int).SetUint64(blockNumber),
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: tracer,
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||
|
||||
@@ -156,7 +156,7 @@ type lru struct {
|
||||
futureItem interface{}
|
||||
}
|
||||
|
||||
// newlru create a new least-recently-used cache for ither the verification caches
|
||||
// newlru create a new least-recently-used cache for either the verification caches
|
||||
// or the mining datasets.
|
||||
func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru {
|
||||
if maxItems <= 0 {
|
||||
|
||||
@@ -618,7 +618,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
|
||||
// If the transaction pool is full, discard underpriced transactions
|
||||
if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
|
||||
// If the new transaction is underpriced, don't accept it
|
||||
if pool.priced.Underpriced(tx, pool.locals) {
|
||||
if !local && pool.priced.Underpriced(tx, pool.locals) {
|
||||
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
|
||||
underpricedTxCounter.Inc(1)
|
||||
return false, ErrUnderpriced
|
||||
|
||||
@@ -1346,7 +1346,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 3)
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
@@ -1406,18 +1406,22 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// Ensure that adding local transactions can push out even higher priced ones
|
||||
tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2])
|
||||
if err := pool.AddLocal(tx); err != nil {
|
||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||
ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to append underpriced local transaction: %v", err)
|
||||
}
|
||||
ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
t.Fatalf("failed to add new underpriced local transaction: %v", err)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
if pending != 3 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
|
||||
}
|
||||
if queued != 2 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||
if queued != 1 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
if err := validateEvents(events, 2); err != nil {
|
||||
t.Fatalf("local event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
|
||||
@@ -139,15 +139,15 @@ func (c *Contract) Value() *big.Int {
|
||||
}
|
||||
|
||||
// SetCode sets the code to the contract
|
||||
func (self *Contract) SetCode(hash common.Hash, code []byte) {
|
||||
self.Code = code
|
||||
self.CodeHash = hash
|
||||
func (c *Contract) SetCode(hash common.Hash, code []byte) {
|
||||
c.Code = code
|
||||
c.CodeHash = hash
|
||||
}
|
||||
|
||||
// SetCallCode sets the code of the contract and address of the backing data
|
||||
// object
|
||||
func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
|
||||
self.Code = code
|
||||
self.CodeHash = hash
|
||||
self.CodeAddr = addr
|
||||
func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
|
||||
c.Code = code
|
||||
c.CodeHash = hash
|
||||
c.CodeAddr = addr
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ import (
|
||||
|
||||
type Storage map[common.Hash]common.Hash
|
||||
|
||||
func (self Storage) Copy() Storage {
|
||||
func (s Storage) Copy() Storage {
|
||||
cpy := make(Storage)
|
||||
for key, value := range self {
|
||||
for key, value := range s {
|
||||
cpy[key] = value
|
||||
}
|
||||
|
||||
|
||||
@@ -51,14 +51,14 @@ func (m *Memory) Resize(size uint64) {
|
||||
}
|
||||
|
||||
// Get returns offset + size as a new slice
|
||||
func (self *Memory) Get(offset, size int64) (cpy []byte) {
|
||||
func (m *Memory) Get(offset, size int64) (cpy []byte) {
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(self.store) > int(offset) {
|
||||
if len(m.store) > int(offset) {
|
||||
cpy = make([]byte, size)
|
||||
copy(cpy, self.store[offset:offset+size])
|
||||
copy(cpy, m.store[offset:offset+size])
|
||||
|
||||
return
|
||||
}
|
||||
@@ -67,13 +67,13 @@ func (self *Memory) Get(offset, size int64) (cpy []byte) {
|
||||
}
|
||||
|
||||
// GetPtr returns the offset + size
|
||||
func (self *Memory) GetPtr(offset, size int64) []byte {
|
||||
func (m *Memory) GetPtr(offset, size int64) []byte {
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(self.store) > int(offset) {
|
||||
return self.store[offset : offset+size]
|
||||
if len(m.store) > int(offset) {
|
||||
return m.store[offset : offset+size]
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -375,10 +375,10 @@ var opCodeToString = map[OpCode]string{
|
||||
SWAP: "SWAP",
|
||||
}
|
||||
|
||||
func (o OpCode) String() string {
|
||||
str := opCodeToString[o]
|
||||
func (op OpCode) String() string {
|
||||
str := opCodeToString[op]
|
||||
if len(str) == 0 {
|
||||
return fmt.Sprintf("Missing opcode 0x%x", int(o))
|
||||
return fmt.Sprintf("Missing opcode 0x%x", int(op))
|
||||
}
|
||||
|
||||
return str
|
||||
|
||||
@@ -325,13 +325,13 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||
return common.Address{}, fmt.Errorf("etherbase must be explicitly specified")
|
||||
}
|
||||
|
||||
// set in js console via admin interface or wrapper from cli flags
|
||||
func (self *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||
self.lock.Lock()
|
||||
self.etherbase = etherbase
|
||||
self.lock.Unlock()
|
||||
// SetEtherbase sets the mining reward address.
|
||||
func (s *Ethereum) SetEtherbase(etherbase common.Address) {
|
||||
s.lock.Lock()
|
||||
s.etherbase = etherbase
|
||||
s.lock.Unlock()
|
||||
|
||||
self.miner.SetEtherbase(etherbase)
|
||||
s.miner.SetEtherbase(etherbase)
|
||||
}
|
||||
|
||||
func (s *Ethereum) StartMining(local bool) error {
|
||||
|
||||
@@ -725,25 +725,25 @@ func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction)
|
||||
}
|
||||
|
||||
// Mined broadcast loop
|
||||
func (self *ProtocolManager) minedBroadcastLoop() {
|
||||
func (pm *ProtocolManager) minedBroadcastLoop() {
|
||||
// automatically stops if unsubscribe
|
||||
for obj := range self.minedBlockSub.Chan() {
|
||||
for obj := range pm.minedBlockSub.Chan() {
|
||||
switch ev := obj.Data.(type) {
|
||||
case core.NewMinedBlockEvent:
|
||||
self.BroadcastBlock(ev.Block, true) // First propagate block to peers
|
||||
self.BroadcastBlock(ev.Block, false) // Only then announce to the rest
|
||||
pm.BroadcastBlock(ev.Block, true) // First propagate block to peers
|
||||
pm.BroadcastBlock(ev.Block, false) // Only then announce to the rest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ProtocolManager) txBroadcastLoop() {
|
||||
func (pm *ProtocolManager) txBroadcastLoop() {
|
||||
for {
|
||||
select {
|
||||
case event := <-self.txCh:
|
||||
self.BroadcastTx(event.Tx.Hash(), event.Tx)
|
||||
case event := <-pm.txCh:
|
||||
pm.BroadcastTx(event.Tx.Hash(), event.Tx)
|
||||
|
||||
// Err() channel will be closed when unsubscribing.
|
||||
case <-self.txSub.Err():
|
||||
case <-pm.txSub.Err():
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -760,13 +760,13 @@ type NodeInfo struct {
|
||||
}
|
||||
|
||||
// NodeInfo retrieves some protocol metadata about the running host node.
|
||||
func (self *ProtocolManager) NodeInfo() *NodeInfo {
|
||||
currentBlock := self.blockchain.CurrentBlock()
|
||||
func (pm *ProtocolManager) NodeInfo() *NodeInfo {
|
||||
currentBlock := pm.blockchain.CurrentBlock()
|
||||
return &NodeInfo{
|
||||
Network: self.networkId,
|
||||
Difficulty: self.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
||||
Genesis: self.blockchain.Genesis().Hash(),
|
||||
Config: self.blockchain.Config(),
|
||||
Network: pm.networkId,
|
||||
Difficulty: pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()),
|
||||
Genesis: pm.blockchain.Genesis().Hash(),
|
||||
Config: pm.blockchain.Config(),
|
||||
Head: currentBlock.Hash(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,37 +45,37 @@ func New() *Filters {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Filters) Start() {
|
||||
go self.loop()
|
||||
func (f *Filters) Start() {
|
||||
go f.loop()
|
||||
}
|
||||
|
||||
func (self *Filters) Stop() {
|
||||
close(self.quit)
|
||||
func (f *Filters) Stop() {
|
||||
close(f.quit)
|
||||
}
|
||||
|
||||
func (self *Filters) Notify(filter Filter, data interface{}) {
|
||||
self.ch <- FilterEvent{filter, data}
|
||||
func (f *Filters) Notify(filter Filter, data interface{}) {
|
||||
f.ch <- FilterEvent{filter, data}
|
||||
}
|
||||
|
||||
func (self *Filters) Install(watcher Filter) int {
|
||||
self.watchers[self.id] = watcher
|
||||
self.id++
|
||||
func (f *Filters) Install(watcher Filter) int {
|
||||
f.watchers[f.id] = watcher
|
||||
f.id++
|
||||
|
||||
return self.id - 1
|
||||
return f.id - 1
|
||||
}
|
||||
|
||||
func (self *Filters) Uninstall(id int) {
|
||||
delete(self.watchers, id)
|
||||
func (f *Filters) Uninstall(id int) {
|
||||
delete(f.watchers, id)
|
||||
}
|
||||
|
||||
func (self *Filters) loop() {
|
||||
func (f *Filters) loop() {
|
||||
out:
|
||||
for {
|
||||
select {
|
||||
case <-self.quit:
|
||||
case <-f.quit:
|
||||
break out
|
||||
case event := <-self.ch:
|
||||
for _, watcher := range self.watchers {
|
||||
case event := <-f.ch:
|
||||
for _, watcher := range f.watchers {
|
||||
if reflect.TypeOf(watcher) == reflect.TypeOf(event.filter) {
|
||||
if watcher.Compare(event.filter) {
|
||||
watcher.Trigger(event.data)
|
||||
@@ -86,10 +86,10 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Filters) Match(a, b Filter) bool {
|
||||
func (f *Filters) Match(a, b Filter) bool {
|
||||
return reflect.TypeOf(a) == reflect.TypeOf(b) && a.Compare(b)
|
||||
}
|
||||
|
||||
func (self *Filters) Get(i int) Filter {
|
||||
return self.watchers[i]
|
||||
func (f *Filters) Get(i int) Filter {
|
||||
return f.watchers[i]
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ func randomSource() *rand.Rand {
|
||||
// call the functions of the otto vm directly to circumvent the queue. These
|
||||
// functions should be used if and only if running a routine that was already
|
||||
// called from JS through an RPC call.
|
||||
func (self *JSRE) runEventLoop() {
|
||||
defer close(self.closed)
|
||||
func (re *JSRE) runEventLoop() {
|
||||
defer close(re.closed)
|
||||
|
||||
vm := otto.New()
|
||||
r := randomSource()
|
||||
@@ -202,14 +202,14 @@ loop:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
case req := <-self.evalQueue:
|
||||
case req := <-re.evalQueue:
|
||||
// run the code, send the result back
|
||||
req.fn(vm)
|
||||
close(req.done)
|
||||
if waitForCallbacks && (len(registry) == 0) {
|
||||
break loop
|
||||
}
|
||||
case waitForCallbacks = <-self.stopEventLoop:
|
||||
case waitForCallbacks = <-re.stopEventLoop:
|
||||
if !waitForCallbacks || (len(registry) == 0) {
|
||||
break loop
|
||||
}
|
||||
@@ -223,31 +223,31 @@ loop:
|
||||
}
|
||||
|
||||
// Do executes the given function on the JS event loop.
|
||||
func (self *JSRE) Do(fn func(*otto.Otto)) {
|
||||
func (re *JSRE) Do(fn func(*otto.Otto)) {
|
||||
done := make(chan bool)
|
||||
req := &evalReq{fn, done}
|
||||
self.evalQueue <- req
|
||||
re.evalQueue <- req
|
||||
<-done
|
||||
}
|
||||
|
||||
// stops the event loop before exit, optionally waits for all timers to expire
|
||||
func (self *JSRE) Stop(waitForCallbacks bool) {
|
||||
func (re *JSRE) Stop(waitForCallbacks bool) {
|
||||
select {
|
||||
case <-self.closed:
|
||||
case self.stopEventLoop <- waitForCallbacks:
|
||||
<-self.closed
|
||||
case <-re.closed:
|
||||
case re.stopEventLoop <- waitForCallbacks:
|
||||
<-re.closed
|
||||
}
|
||||
}
|
||||
|
||||
// Exec(file) loads and runs the contents of a file
|
||||
// if a relative path is given, the jsre's assetPath is used
|
||||
func (self *JSRE) Exec(file string) error {
|
||||
code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file))
|
||||
func (re *JSRE) Exec(file string) error {
|
||||
code, err := ioutil.ReadFile(common.AbsolutePath(re.assetPath, file))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var script *otto.Script
|
||||
self.Do(func(vm *otto.Otto) {
|
||||
re.Do(func(vm *otto.Otto) {
|
||||
script, err = vm.Compile(file, code)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -259,36 +259,36 @@ func (self *JSRE) Exec(file string) error {
|
||||
|
||||
// Bind assigns value v to a variable in the JS environment
|
||||
// This method is deprecated, use Set.
|
||||
func (self *JSRE) Bind(name string, v interface{}) error {
|
||||
return self.Set(name, v)
|
||||
func (re *JSRE) Bind(name string, v interface{}) error {
|
||||
return re.Set(name, v)
|
||||
}
|
||||
|
||||
// Run runs a piece of JS code.
|
||||
func (self *JSRE) Run(code string) (v otto.Value, err error) {
|
||||
self.Do(func(vm *otto.Otto) { v, err = vm.Run(code) })
|
||||
func (re *JSRE) Run(code string) (v otto.Value, err error) {
|
||||
re.Do(func(vm *otto.Otto) { v, err = vm.Run(code) })
|
||||
return v, err
|
||||
}
|
||||
|
||||
// Get returns the value of a variable in the JS environment.
|
||||
func (self *JSRE) Get(ns string) (v otto.Value, err error) {
|
||||
self.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) })
|
||||
func (re *JSRE) Get(ns string) (v otto.Value, err error) {
|
||||
re.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) })
|
||||
return v, err
|
||||
}
|
||||
|
||||
// Set assigns value v to a variable in the JS environment.
|
||||
func (self *JSRE) Set(ns string, v interface{}) (err error) {
|
||||
self.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) })
|
||||
func (re *JSRE) Set(ns string, v interface{}) (err error) {
|
||||
re.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) })
|
||||
return err
|
||||
}
|
||||
|
||||
// loadScript executes a JS script from inside the currently executing JS code.
|
||||
func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
|
||||
func (re *JSRE) loadScript(call otto.FunctionCall) otto.Value {
|
||||
file, err := call.Argument(0).ToString()
|
||||
if err != nil {
|
||||
// TODO: throw exception
|
||||
return otto.FalseValue()
|
||||
}
|
||||
file = common.AbsolutePath(self.assetPath, file)
|
||||
file = common.AbsolutePath(re.assetPath, file)
|
||||
source, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
// TODO: throw exception
|
||||
@@ -305,10 +305,10 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
|
||||
|
||||
// Evaluate executes code and pretty prints the result to the specified output
|
||||
// stream.
|
||||
func (self *JSRE) Evaluate(code string, w io.Writer) error {
|
||||
func (re *JSRE) Evaluate(code string, w io.Writer) error {
|
||||
var fail error
|
||||
|
||||
self.Do(func(vm *otto.Otto) {
|
||||
re.Do(func(vm *otto.Otto) {
|
||||
val, err := vm.Run(code)
|
||||
if err != nil {
|
||||
prettyError(vm, err, w)
|
||||
@@ -321,8 +321,8 @@ func (self *JSRE) Evaluate(code string, w io.Writer) error {
|
||||
}
|
||||
|
||||
// Compile compiles and then runs a piece of JS code.
|
||||
func (self *JSRE) Compile(filename string, src interface{}) (err error) {
|
||||
self.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) })
|
||||
func (re *JSRE) Compile(filename string, src interface{}) (err error) {
|
||||
re.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) })
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,8 @@ func (p *testDistPeer) waitBefore(cost uint64) (time.Duration, float64) {
|
||||
p.lock.RUnlock()
|
||||
if sumCost < testDistBufLimit {
|
||||
return 0, float64(testDistBufLimit-sumCost) / float64(testDistBufLimit)
|
||||
} else {
|
||||
return time.Duration(sumCost - testDistBufLimit), 0
|
||||
}
|
||||
return time.Duration(sumCost - testDistBufLimit), 0
|
||||
}
|
||||
|
||||
func (p *testDistPeer) canQueue() bool {
|
||||
|
||||
@@ -160,9 +160,8 @@ func (a *announceData) checkSignature(pubKey *ecdsa.PublicKey) error {
|
||||
pbytes := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
|
||||
if bytes.Equal(pbytes, recPubkey) {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("Wrong signature")
|
||||
}
|
||||
return errors.New("Wrong signature")
|
||||
}
|
||||
|
||||
type blockInfo struct {
|
||||
|
||||
@@ -118,17 +118,16 @@ func (n *wrsNode) insert(item wrsItem, weight int64) int {
|
||||
if n.level == 0 {
|
||||
n.items[branch] = item
|
||||
return branch
|
||||
} else {
|
||||
var subNode *wrsNode
|
||||
if n.items[branch] == nil {
|
||||
subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1}
|
||||
n.items[branch] = subNode
|
||||
} else {
|
||||
subNode = n.items[branch].(*wrsNode)
|
||||
}
|
||||
subIdx := subNode.insert(item, weight)
|
||||
return subNode.maxItems*branch + subIdx
|
||||
}
|
||||
var subNode *wrsNode
|
||||
if n.items[branch] == nil {
|
||||
subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1}
|
||||
n.items[branch] = subNode
|
||||
} else {
|
||||
subNode = n.items[branch].(*wrsNode)
|
||||
}
|
||||
subIdx := subNode.insert(item, weight)
|
||||
return subNode.maxItems*branch + subIdx
|
||||
}
|
||||
|
||||
// setWeight updates the weight of a certain item (which should exist) and returns
|
||||
@@ -162,12 +161,10 @@ func (n *wrsNode) choose(val int64) (wrsItem, int64) {
|
||||
if val < w {
|
||||
if n.level == 0 {
|
||||
return n.items[i].(wrsItem), n.weights[i]
|
||||
} else {
|
||||
return n.items[i].(*wrsNode).choose(val)
|
||||
}
|
||||
} else {
|
||||
val -= w
|
||||
return n.items[i].(*wrsNode).choose(val)
|
||||
}
|
||||
val -= w
|
||||
}
|
||||
panic(nil)
|
||||
}
|
||||
|
||||
@@ -601,9 +601,8 @@ func (e *discoveredEntry) Weight() int64 {
|
||||
t := time.Duration(mclock.Now() - e.lastDiscovered)
|
||||
if t <= discoverExpireStart {
|
||||
return 1000000000
|
||||
} else {
|
||||
return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst)))
|
||||
}
|
||||
return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst)))
|
||||
}
|
||||
|
||||
// knownEntry implements wrsItem
|
||||
|
||||
@@ -234,9 +234,8 @@ func FailoverHandler(hs ...Handler) Handler {
|
||||
err = h.Log(r)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else {
|
||||
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
|
||||
}
|
||||
r.Ctx = append(r.Ctx, fmt.Sprintf("failover_err_%d", i), err)
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -320,13 +319,12 @@ func evaluateLazy(lz Lazy) (interface{}, error) {
|
||||
results := value.Call([]reflect.Value{})
|
||||
if len(results) == 1 {
|
||||
return results[0].Interface(), nil
|
||||
} else {
|
||||
values := make([]interface{}, len(results))
|
||||
for i, v := range results {
|
||||
values[i] = v.Interface()
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
values := make([]interface{}, len(results))
|
||||
for i, v := range results {
|
||||
values[i] = v.Interface()
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// DiscardHandler reports success for all writes but does nothing.
|
||||
|
||||
@@ -65,7 +65,7 @@ type Batch struct {
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
func (self *LibratoClient) PostMetrics(batch Batch) (err error) {
|
||||
func (c *LibratoClient) PostMetrics(batch Batch) (err error) {
|
||||
var (
|
||||
js []byte
|
||||
req *http.Request
|
||||
@@ -85,7 +85,7 @@ func (self *LibratoClient) PostMetrics(batch Batch) (err error) {
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.SetBasicAuth(self.Email, self.Token)
|
||||
req.SetBasicAuth(c.Email, c.Token)
|
||||
|
||||
if resp, err = http.DefaultClient.Do(req); err != nil {
|
||||
return
|
||||
|
||||
@@ -40,14 +40,14 @@ func Librato(r metrics.Registry, d time.Duration, e string, t string, s string,
|
||||
NewReporter(r, d, e, t, s, p, u).Run()
|
||||
}
|
||||
|
||||
func (self *Reporter) Run() {
|
||||
func (rep *Reporter) Run() {
|
||||
log.Printf("WARNING: This client has been DEPRECATED! It has been moved to https://github.com/mihasya/go-metrics-librato and will be removed from rcrowley/go-metrics on August 5th 2015")
|
||||
ticker := time.Tick(self.Interval)
|
||||
metricsApi := &LibratoClient{self.Email, self.Token}
|
||||
ticker := time.Tick(rep.Interval)
|
||||
metricsApi := &LibratoClient{rep.Email, rep.Token}
|
||||
for now := range ticker {
|
||||
var metrics Batch
|
||||
var err error
|
||||
if metrics, err = self.BuildRequest(now, self.Registry); err != nil {
|
||||
if metrics, err = rep.BuildRequest(now, rep.Registry); err != nil {
|
||||
log.Printf("ERROR constructing librato request body %s", err)
|
||||
continue
|
||||
}
|
||||
@@ -79,21 +79,21 @@ func sumSquaresTimer(t metrics.Timer) float64 {
|
||||
return sumSquares
|
||||
}
|
||||
|
||||
func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) {
|
||||
func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot Batch, err error) {
|
||||
snapshot = Batch{
|
||||
// coerce timestamps to a stepping fn so that they line up in Librato graphs
|
||||
MeasureTime: (now.Unix() / self.intervalSec) * self.intervalSec,
|
||||
Source: self.Source,
|
||||
MeasureTime: (now.Unix() / rep.intervalSec) * rep.intervalSec,
|
||||
Source: rep.Source,
|
||||
}
|
||||
snapshot.Gauges = make([]Measurement, 0)
|
||||
snapshot.Counters = make([]Measurement, 0)
|
||||
histogramGaugeCount := 1 + len(self.Percentiles)
|
||||
histogramGaugeCount := 1 + len(rep.Percentiles)
|
||||
r.Each(func(name string, metric interface{}) {
|
||||
if self.Namespace != "" {
|
||||
name = fmt.Sprintf("%s.%s", self.Namespace, name)
|
||||
if rep.Namespace != "" {
|
||||
name = fmt.Sprintf("%s.%s", rep.Namespace, name)
|
||||
}
|
||||
measurement := Measurement{}
|
||||
measurement[Period] = self.Interval.Seconds()
|
||||
measurement[Period] = rep.Interval.Seconds()
|
||||
switch m := metric.(type) {
|
||||
case metrics.Counter:
|
||||
if m.Count() > 0 {
|
||||
@@ -125,7 +125,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
measurement[Sum] = float64(s.Sum())
|
||||
measurement[SumSquares] = sumSquares(s)
|
||||
gauges[0] = measurement
|
||||
for i, p := range self.Percentiles {
|
||||
for i, p := range rep.Percentiles {
|
||||
gauges[i+1] = Measurement{
|
||||
Name: fmt.Sprintf("%s.%.2f", measurement[Name], p),
|
||||
Value: s.Percentile(p),
|
||||
@@ -142,7 +142,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "1min"),
|
||||
Value: m.Rate1(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
@@ -152,7 +152,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "5min"),
|
||||
Value: m.Rate5(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
@@ -162,7 +162,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "15min"),
|
||||
Value: m.Rate15(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
@@ -184,15 +184,15 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Max: float64(m.Max()),
|
||||
Min: float64(m.Min()),
|
||||
SumSquares: sumSquaresTimer(m),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Attributes: self.TimerAttributes,
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: rep.TimerAttributes,
|
||||
}
|
||||
for i, p := range self.Percentiles {
|
||||
for i, p := range rep.Percentiles {
|
||||
gauges[i+1] = Measurement{
|
||||
Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100),
|
||||
Value: m.Percentile(p),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Attributes: self.TimerAttributes,
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: rep.TimerAttributes,
|
||||
}
|
||||
}
|
||||
snapshot.Gauges = append(snapshot.Gauges, gauges...)
|
||||
@@ -200,7 +200,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "rate.1min"),
|
||||
Value: m.Rate1(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
@@ -210,7 +210,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "rate.5min"),
|
||||
Value: m.Rate5(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
@@ -220,7 +220,7 @@ func (self *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot
|
||||
Measurement{
|
||||
Name: fmt.Sprintf("%s.%s", name, "rate.15min"),
|
||||
Value: m.Rate15(),
|
||||
Period: int64(self.Interval.Seconds()),
|
||||
Period: int64(rep.Interval.Seconds()),
|
||||
Attributes: map[string]interface{}{
|
||||
DisplayUnitsLong: Operations,
|
||||
DisplayUnitsShort: OperationsShort,
|
||||
|
||||
@@ -229,21 +229,20 @@ func ExpectMsg(r MsgReader, code uint64, content interface{}) error {
|
||||
}
|
||||
if content == nil {
|
||||
return msg.Discard()
|
||||
} else {
|
||||
contentEnc, err := rlp.EncodeToBytes(content)
|
||||
if err != nil {
|
||||
panic("content encode error: " + err.Error())
|
||||
}
|
||||
if int(msg.Size) != len(contentEnc) {
|
||||
return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc))
|
||||
}
|
||||
actualContent, err := ioutil.ReadAll(msg.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(actualContent, contentEnc) {
|
||||
return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc)
|
||||
}
|
||||
}
|
||||
contentEnc, err := rlp.EncodeToBytes(content)
|
||||
if err != nil {
|
||||
panic("content encode error: " + err.Error())
|
||||
}
|
||||
if int(msg.Size) != len(contentEnc) {
|
||||
return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc))
|
||||
}
|
||||
actualContent, err := ioutil.ReadAll(msg.Payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(actualContent, contentEnc) {
|
||||
return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -738,7 +738,6 @@ func (self *Network) executeNodeEvent(e *Event) error {
|
||||
func (self *Network) executeConnEvent(e *Event) error {
|
||||
if e.Conn.Up {
|
||||
return self.Connect(e.Conn.One, e.Conn.Other)
|
||||
} else {
|
||||
return self.Disconnect(e.Conn.One, e.Conn.Other)
|
||||
}
|
||||
return self.Disconnect(e.Conn.One, e.Conn.Other)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 8 // Minor version component of the current release
|
||||
VersionPatch = 7 // Patch version component of the current release
|
||||
VersionPatch = 8 // Patch version component of the current release
|
||||
VersionMeta = "unstable" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer codec.Close()
|
||||
|
||||
w.Header().Set("content-type", contentType)
|
||||
srv.ServeSingleRequest(codec, OptionMethodInvocation, ctx)
|
||||
srv.ServeSingleRequest(ctx, codec, OptionMethodInvocation)
|
||||
}
|
||||
|
||||
// validateRequest returns a non-zero response code and error message if the
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// NewInProcClient attaches an in-process connection to the given RPC server.
|
||||
// DialInProc attaches an in-process connection to the given RPC server.
|
||||
func DialInProc(handler *Server) *Client {
|
||||
initctx := context.Background()
|
||||
c, _ := newClient(initctx, func(context.Context) (net.Conn, error) {
|
||||
|
||||
@@ -125,7 +125,7 @@ func (s *Server) RegisterName(name string, rcvr interface{}) error {
|
||||
// If singleShot is true it will process a single request, otherwise it will handle
|
||||
// requests until the codec returns an error when reading a request (in most cases
|
||||
// an EOF). It executes requests in parallel when singleShot is false.
|
||||
func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecOption, ctx context.Context) error {
|
||||
func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot bool, options CodecOption) error {
|
||||
var pend sync.WaitGroup
|
||||
|
||||
defer func() {
|
||||
@@ -216,14 +216,14 @@ func (s *Server) serveRequest(codec ServerCodec, singleShot bool, options CodecO
|
||||
// stopped. In either case the codec is closed.
|
||||
func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) {
|
||||
defer codec.Close()
|
||||
s.serveRequest(codec, false, options, context.Background())
|
||||
s.serveRequest(context.Background(), codec, false, options)
|
||||
}
|
||||
|
||||
// ServeSingleRequest reads and processes a single RPC request from the given codec. It will not
|
||||
// close the codec unless a non-recoverable error has occurred. Note, this method will return after
|
||||
// a single request has been processed!
|
||||
func (s *Server) ServeSingleRequest(codec ServerCodec, options CodecOption, ctx context.Context) {
|
||||
s.serveRequest(codec, true, options, ctx)
|
||||
func (s *Server) ServeSingleRequest(ctx context.Context, codec ServerCodec, options CodecOption) {
|
||||
s.serveRequest(ctx, codec, true, options)
|
||||
}
|
||||
|
||||
// Stop will stop reading new requests, wait for stopPendingRequestTimeout to allow pending requests to finish,
|
||||
|
||||
@@ -94,13 +94,12 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
|
||||
for n, argument := range method.Inputs {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
|
||||
} else {
|
||||
decodedArg := decodedArgument{
|
||||
soltype: argument,
|
||||
value: v[n],
|
||||
}
|
||||
decoded.inputs = append(decoded.inputs, decodedArg)
|
||||
}
|
||||
decodedArg := decodedArgument{
|
||||
soltype: argument,
|
||||
value: v[n],
|
||||
}
|
||||
decoded.inputs = append(decoded.inputs, decodedArg)
|
||||
}
|
||||
|
||||
// We're finished decoding the data. At this point, we encode the decoded data to see if it matches with the
|
||||
@@ -240,7 +239,7 @@ func (db *AbiDb) saveCustomAbi(selector, signature string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Adds a signature to the database, if custom database saving is enabled.
|
||||
// AddSignature to the database, if custom database saving is enabled.
|
||||
// OBS: This method does _not_ validate the correctness of the data,
|
||||
// it is assumed that the caller has already done so
|
||||
func (db *AbiDb) AddSignature(selector string, data []byte) error {
|
||||
|
||||
@@ -474,7 +474,7 @@ func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.Raw
|
||||
return ioutil.ReadFile(wallet.URL().Path)
|
||||
}
|
||||
|
||||
// Imports tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
|
||||
// Import tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
|
||||
// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful
|
||||
// decryption it will encrypt the key with the given newPassphrase and store it in the keystore.
|
||||
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
import (
|
||||
|
||||
@@ -73,8 +73,8 @@ type SendTxArgs struct {
|
||||
Input *hexutil.Bytes `json:"input"`
|
||||
}
|
||||
|
||||
func (t SendTxArgs) String() string {
|
||||
s, err := json.Marshal(t)
|
||||
func (args SendTxArgs) String() string {
|
||||
s, err := json.Marshal(args)
|
||||
if err == nil {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ func (v *Validator) validate(msgs *ValidationMessages, txargs *SendTxArgs, metho
|
||||
if len(data) == 0 {
|
||||
if txargs.Value.ToInt().Cmp(big.NewInt(0)) > 0 {
|
||||
// Sending ether into black hole
|
||||
return errors.New(`Tx will create contract with value but empty code!`)
|
||||
return errors.New("Tx will create contract with value but empty code!")
|
||||
}
|
||||
// No value submitted at least
|
||||
msgs.crit("Tx will create contract with empty code!")
|
||||
|
||||
@@ -46,17 +46,17 @@ func consoleOutput(call otto.FunctionCall) otto.Value {
|
||||
return otto.Value{}
|
||||
}
|
||||
|
||||
// rulesetUi provides an implementation of SignerUI that evaluates a javascript
|
||||
// rulesetUI provides an implementation of SignerUI that evaluates a javascript
|
||||
// file for each defined UI-method
|
||||
type rulesetUi struct {
|
||||
type rulesetUI struct {
|
||||
next core.SignerUI // The next handler, for manual processing
|
||||
storage storage.Storage
|
||||
credentials storage.Storage
|
||||
jsRules string // The rules to use
|
||||
}
|
||||
|
||||
func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.Storage) (*rulesetUi, error) {
|
||||
c := &rulesetUi{
|
||||
func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.Storage) (*rulesetUI, error) {
|
||||
c := &rulesetUI{
|
||||
next: next,
|
||||
storage: jsbackend,
|
||||
credentials: credentialsBackend,
|
||||
@@ -66,11 +66,11 @@ func NewRuleEvaluator(next core.SignerUI, jsbackend, credentialsBackend storage.
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (r *rulesetUi) Init(javascriptRules string) error {
|
||||
func (r *rulesetUI) Init(javascriptRules string) error {
|
||||
r.jsRules = javascriptRules
|
||||
return nil
|
||||
}
|
||||
func (r *rulesetUi) execute(jsfunc string, jsarg interface{}) (otto.Value, error) {
|
||||
func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error) {
|
||||
|
||||
// Instantiate a fresh vm engine every time
|
||||
vm := otto.New()
|
||||
@@ -115,7 +115,7 @@ func (r *rulesetUi) execute(jsfunc string, jsarg interface{}) (otto.Value, error
|
||||
return vm.Run(call)
|
||||
}
|
||||
|
||||
func (r *rulesetUi) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) {
|
||||
func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func (r *rulesetUi) checkApproval(jsfunc string, jsarg []byte, err error) (bool,
|
||||
return false, fmt.Errorf("Unknown response")
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
func (r *rulesetUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
jsonreq, err := json.Marshal(request)
|
||||
approved, err := r.checkApproval("ApproveTx", jsonreq, err)
|
||||
if err != nil {
|
||||
@@ -158,11 +158,11 @@ func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse,
|
||||
return core.SignTxResponse{Approved: false}, err
|
||||
}
|
||||
|
||||
func (r *rulesetUi) lookupPassword(address common.Address) string {
|
||||
func (r *rulesetUI) lookupPassword(address common.Address) string {
|
||||
return r.credentials.Get(strings.ToLower(address.String()))
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
func (r *rulesetUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
jsonreq, err := json.Marshal(request)
|
||||
approved, err := r.checkApproval("ApproveSignData", jsonreq, err)
|
||||
if err != nil {
|
||||
@@ -175,7 +175,7 @@ func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDat
|
||||
return core.SignDataResponse{Approved: false, Password: ""}, err
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
func (r *rulesetUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
jsonreq, err := json.Marshal(request)
|
||||
approved, err := r.checkApproval("ApproveExport", jsonreq, err)
|
||||
if err != nil {
|
||||
@@ -188,13 +188,13 @@ func (r *rulesetUi) ApproveExport(request *core.ExportRequest) (core.ExportRespo
|
||||
return core.ExportResponse{Approved: false}, err
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
func (r *rulesetUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
// This cannot be handled by rules, requires setting a password
|
||||
// dispatch to next
|
||||
return r.next.ApproveImport(request)
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
func (r *rulesetUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
jsonreq, err := json.Marshal(request)
|
||||
approved, err := r.checkApproval("ApproveListing", jsonreq, err)
|
||||
if err != nil {
|
||||
@@ -207,22 +207,22 @@ func (r *rulesetUi) ApproveListing(request *core.ListRequest) (core.ListResponse
|
||||
return core.ListResponse{}, err
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
func (r *rulesetUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
// This cannot be handled by rules, requires setting a password
|
||||
// dispatch to next
|
||||
return r.next.ApproveNewAccount(request)
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ShowError(message string) {
|
||||
func (r *rulesetUI) ShowError(message string) {
|
||||
log.Error(message)
|
||||
r.next.ShowError(message)
|
||||
}
|
||||
|
||||
func (r *rulesetUi) ShowInfo(message string) {
|
||||
func (r *rulesetUI) ShowInfo(message string) {
|
||||
log.Info(message)
|
||||
r.next.ShowInfo(message)
|
||||
}
|
||||
func (r *rulesetUi) OnSignerStartup(info core.StartupInfo) {
|
||||
func (r *rulesetUI) OnSignerStartup(info core.StartupInfo) {
|
||||
jsonInfo, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
log.Warn("failed marshalling data", "data", info)
|
||||
@@ -235,7 +235,7 @@ func (r *rulesetUi) OnSignerStartup(info core.StartupInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rulesetUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
func (r *rulesetUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
jsonTx, err := json.Marshal(tx)
|
||||
if err != nil {
|
||||
log.Warn("failed marshalling transaction", "tx", tx)
|
||||
|
||||
@@ -33,18 +33,18 @@ import (
|
||||
|
||||
const JS = `
|
||||
/**
|
||||
This is an example implementation of a Javascript rule file.
|
||||
This is an example implementation of a Javascript rule file.
|
||||
|
||||
When the signer receives a request over the external API, the corresponding method is evaluated.
|
||||
Three things can happen:
|
||||
When the signer receives a request over the external API, the corresponding method is evaluated.
|
||||
Three things can happen:
|
||||
|
||||
1. The method returns "Approve". This means the operation is permitted.
|
||||
2. The method returns "Reject". This means the operation is rejected.
|
||||
1. The method returns "Approve". This means the operation is permitted.
|
||||
2. The method returns "Reject". This means the operation is rejected.
|
||||
3. Anything else; other return values [*], method not implemented or exception occurred during processing. This means
|
||||
that the operation will continue to manual processing, via the regular UI method chosen by the user.
|
||||
that the operation will continue to manual processing, via the regular UI method chosen by the user.
|
||||
|
||||
[*] Note: Future version of the ruleset may use more complex json-based returnvalues, making it possible to not
|
||||
only respond Approve/Reject/Manual, but also modify responses. For example, choose to list only one, but not all
|
||||
[*] Note: Future version of the ruleset may use more complex json-based returnvalues, making it possible to not
|
||||
only respond Approve/Reject/Manual, but also modify responses. For example, choose to list only one, but not all
|
||||
accounts in a list-request. The points above will continue to hold for non-json based responses ("Approve"/"Reject").
|
||||
|
||||
**/
|
||||
@@ -72,49 +72,49 @@ func mixAddr(a string) (*common.MixedcaseAddress, error) {
|
||||
return common.NewMixedcaseAddressFromString(a)
|
||||
}
|
||||
|
||||
type alwaysDenyUi struct{}
|
||||
type alwaysDenyUI struct{}
|
||||
|
||||
func (alwaysDenyUi) OnSignerStartup(info core.StartupInfo) {
|
||||
func (alwaysDenyUI) OnSignerStartup(info core.StartupInfo) {
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
func (alwaysDenyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
return core.SignTxResponse{Transaction: request.Transaction, Approved: false, Password: ""}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
func (alwaysDenyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
return core.SignDataResponse{Approved: false, Password: ""}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
func (alwaysDenyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
return core.ExportResponse{Approved: false}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
func (alwaysDenyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
return core.ImportResponse{Approved: false, OldPassword: "", NewPassword: ""}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
func (alwaysDenyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
return core.ListResponse{Accounts: nil}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
func (alwaysDenyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
return core.NewAccountResponse{Approved: false, Password: ""}, nil
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ShowError(message string) {
|
||||
func (alwaysDenyUI) ShowError(message string) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) ShowInfo(message string) {
|
||||
func (alwaysDenyUI) ShowInfo(message string) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (alwaysDenyUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
func (alwaysDenyUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func initRuleEngine(js string) (*rulesetUi, error) {
|
||||
r, err := NewRuleEvaluator(&alwaysDenyUi{}, storage.NewEphemeralStorage(), storage.NewEphemeralStorage())
|
||||
func initRuleEngine(js string) (*rulesetUI, error) {
|
||||
r, err := NewRuleEvaluator(&alwaysDenyUI{}, storage.NewEphemeralStorage(), storage.NewEphemeralStorage())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create js engine: %v", err)
|
||||
}
|
||||
@@ -196,59 +196,59 @@ func TestSignTxRequest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type dummyUi struct {
|
||||
type dummyUI struct {
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
func (d *dummyUI) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveTx")
|
||||
return core.SignTxResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
func (d *dummyUI) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveSignData")
|
||||
return core.SignDataResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
func (d *dummyUI) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveExport")
|
||||
return core.ExportResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
func (d *dummyUI) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveImport")
|
||||
return core.ImportResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
func (d *dummyUI) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveListing")
|
||||
return core.ListResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
func (d *dummyUI) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
|
||||
d.calls = append(d.calls, "ApproveNewAccount")
|
||||
return core.NewAccountResponse{}, core.ErrRequestDenied
|
||||
}
|
||||
|
||||
func (d *dummyUi) ShowError(message string) {
|
||||
func (d *dummyUI) ShowError(message string) {
|
||||
d.calls = append(d.calls, "ShowError")
|
||||
}
|
||||
|
||||
func (d *dummyUi) ShowInfo(message string) {
|
||||
func (d *dummyUI) ShowInfo(message string) {
|
||||
d.calls = append(d.calls, "ShowInfo")
|
||||
}
|
||||
|
||||
func (d *dummyUi) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
|
||||
d.calls = append(d.calls, "OnApprovedTx")
|
||||
}
|
||||
func (d *dummyUi) OnSignerStartup(info core.StartupInfo) {
|
||||
func (d *dummyUI) OnSignerStartup(info core.StartupInfo) {
|
||||
}
|
||||
|
||||
//TestForwarding tests that the rule-engine correctly dispatches requests to the next caller
|
||||
func TestForwarding(t *testing.T) {
|
||||
|
||||
js := ""
|
||||
ui := &dummyUi{make([]string, 0)}
|
||||
ui := &dummyUI{make([]string, 0)}
|
||||
jsBackend := storage.NewEphemeralStorage()
|
||||
credBackend := storage.NewEphemeralStorage()
|
||||
r, err := NewRuleEvaluator(ui, jsBackend, credBackend)
|
||||
@@ -308,22 +308,22 @@ func TestStorage(t *testing.T) {
|
||||
function testStorage(){
|
||||
storage.Put("mykey", "myvalue")
|
||||
a = storage.Get("mykey")
|
||||
|
||||
|
||||
storage.Put("mykey", ["a", "list"]) // Should result in "a,list"
|
||||
a += storage.Get("mykey")
|
||||
|
||||
|
||||
|
||||
storage.Put("mykey", {"an": "object"}) // Should result in "[object Object]"
|
||||
a += storage.Get("mykey")
|
||||
|
||||
|
||||
|
||||
storage.Put("mykey", JSON.stringify({"an": "object"})) // Should result in '{"an":"object"}'
|
||||
a += storage.Get("mykey")
|
||||
|
||||
a += storage.Get("missingkey") //Missing keys should result in empty string
|
||||
storage.Put("","missing key==noop") // Can't store with 0-length key
|
||||
a += storage.Get("") // Should result in ''
|
||||
|
||||
|
||||
var b = new BigNumber(2)
|
||||
var c = new BigNumber(16)//"0xf0",16)
|
||||
var d = b.plus(c)
|
||||
@@ -361,7 +361,7 @@ const ExampleTxWindow = `
|
||||
if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)}
|
||||
return new BigNumber(str)
|
||||
}
|
||||
|
||||
|
||||
// Time window: 1 week
|
||||
var window = 1000* 3600*24*7;
|
||||
|
||||
@@ -370,7 +370,7 @@ const ExampleTxWindow = `
|
||||
|
||||
function isLimitOk(transaction){
|
||||
var value = big(transaction.value)
|
||||
// Start of our window function
|
||||
// Start of our window function
|
||||
var windowstart = new Date().getTime() - window;
|
||||
|
||||
var txs = [];
|
||||
@@ -382,17 +382,17 @@ const ExampleTxWindow = `
|
||||
// First, remove all that have passed out of the time-window
|
||||
var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart});
|
||||
console.log(txs, newtxs.length);
|
||||
|
||||
|
||||
// Secondly, aggregate the current sum
|
||||
sum = new BigNumber(0)
|
||||
|
||||
sum = newtxs.reduce(function(agg, tx){ return big(tx.value).plus(agg)}, sum);
|
||||
console.log("ApproveTx > Sum so far", sum);
|
||||
console.log("ApproveTx > Requested", value.toNumber());
|
||||
|
||||
|
||||
// Would we exceed weekly limit ?
|
||||
return sum.plus(value).lt(limit)
|
||||
|
||||
|
||||
}
|
||||
function ApproveTx(r){
|
||||
console.log(r)
|
||||
@@ -405,14 +405,14 @@ const ExampleTxWindow = `
|
||||
|
||||
/**
|
||||
* OnApprovedTx(str) is called when a transaction has been approved and signed. The parameter
|
||||
* 'response_str' contains the return value that will be sent to the external caller.
|
||||
* The return value from this method is ignore - the reason for having this callback is to allow the
|
||||
* ruleset to keep track of approved transactions.
|
||||
* 'response_str' contains the return value that will be sent to the external caller.
|
||||
* The return value from this method is ignore - the reason for having this callback is to allow the
|
||||
* ruleset to keep track of approved transactions.
|
||||
*
|
||||
* When implementing rate-limited rules, this callback should be used.
|
||||
* When implementing rate-limited rules, this callback should be used.
|
||||
* If a rule responds with neither 'Approve' nor 'Reject' - the tx goes to manual processing. If the user
|
||||
* then accepts the transaction, this method will be called.
|
||||
*
|
||||
*
|
||||
* TLDR; Use this method to keep track of signed transactions, instead of using the data in ApproveTx.
|
||||
*/
|
||||
function OnApprovedTx(resp){
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// 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
|
||||
|
||||
import (
|
||||
@@ -106,10 +107,8 @@ func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredentia
|
||||
if os.IsNotExist(err) {
|
||||
// Doesn't exist yet
|
||||
return creds, nil
|
||||
|
||||
} else {
|
||||
log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
|
||||
}
|
||||
log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
|
||||
}
|
||||
if err = json.Unmarshal(raw, &creds); err != nil {
|
||||
log.Warn("Failed to unmarshal encrypted storage", "err", err, "file", s.filename)
|
||||
|
||||
Reference in New Issue
Block a user