mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge commit '225171a4bfcc16bd12a1906b1e0d43d0b18c353b'
This commit is contained in:
commit
ae4f20efbd
506 changed files with 61281 additions and 23278 deletions
1
AUTHORS
1
AUTHORS
|
|
@ -171,3 +171,4 @@ xiekeyang <xiekeyang@users.noreply.github.com>
|
|||
yoza <yoza.is12s@gmail.com>
|
||||
ΞTHΞЯSPHΞЯΞ <{viktor.tron,nagydani,zsfelfoldi}@gmail.com>
|
||||
Максим Чусовлянов <mchusovlianov@gmail.com>
|
||||
Ralph Caraveo <deckarep@gmail.com>
|
||||
|
|
|
|||
1
Makefile
1
Makefile
|
|
@ -41,6 +41,7 @@ lint: ## Run linters.
|
|||
build/env.sh go run build/ci.go lint
|
||||
|
||||
clean:
|
||||
./build/clean_go_build_cache.sh
|
||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||
|
||||
# The devtools target installs tools required for 'go generate'.
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ The go-ethereum project comes with several wrappers/executables found in the `cm
|
|||
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
|
||||
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
|
||||
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
|
||||
| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
|
||||
| `swarm` | Swarm daemon and tools. This is the entrypoint for the Swarm network. `swarm --help` for command line options and subcommands. See [Swarm README](https://github.com/ethereum/go-ethereum/tree/master/swarm) for more information. |
|
||||
| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. |
|
||||
|
||||
## Running geth
|
||||
|
|
|
|||
1
VERSION
1
VERSION
|
|
@ -1 +0,0 @@
|
|||
1.8.13
|
||||
|
|
@ -324,6 +324,11 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
//
|
||||
// TODO(karalabe): Deprecate when the subscription one can return past data too.
|
||||
func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
|
||||
var filter *filters.Filter
|
||||
if query.BlockHash != nil {
|
||||
// Block filter requested, construct a single-shot filter
|
||||
filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
|
||||
} else {
|
||||
// Initialize unset filter boundaried to run from genesis to chain head
|
||||
from := int64(0)
|
||||
if query.FromBlock != nil {
|
||||
|
|
@ -333,9 +338,10 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
|
|||
if query.ToBlock != nil {
|
||||
to = query.ToBlock.Int64()
|
||||
}
|
||||
// Construct and execute the filter
|
||||
filter := filters.New(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
|
||||
|
||||
// Construct the range filter
|
||||
filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
|
||||
}
|
||||
// Run the filter and return all the logs
|
||||
logs, err := filter.Logs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -430,6 +436,10 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
|
|||
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||
return fb.bc.GetHeaderByHash(hash), nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||
number := rawdb.ReadHeaderNumber(fb.db, hash)
|
||||
if number == nil {
|
||||
|
|
|
|||
|
|
@ -47,10 +47,8 @@ type Method struct {
|
|||
// Please note that "int" is substitute for its canonical representation "int256"
|
||||
func (method Method) Sig() string {
|
||||
types := make([]string, len(method.Inputs))
|
||||
i := 0
|
||||
for _, input := range method.Inputs {
|
||||
for i, input := range method.Inputs {
|
||||
types[i] = input.Type.String()
|
||||
i++
|
||||
}
|
||||
return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ","))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"gopkg.in/fatih/set.v0"
|
||||
)
|
||||
|
||||
// Minimum amount of time between cache reloads. This limit applies if the platform does
|
||||
|
|
@ -79,7 +79,7 @@ func newAccountCache(keydir string) (*accountCache, chan struct{}) {
|
|||
keydir: keydir,
|
||||
byAddr: make(map[common.Address][]accounts.Account),
|
||||
notify: make(chan struct{}, 1),
|
||||
fileC: fileCache{all: set.NewNonTS()},
|
||||
fileC: fileCache{all: mapset.NewThreadUnsafeSet()},
|
||||
}
|
||||
ac.watcher = newWatcher(ac)
|
||||
return ac, ac.notify
|
||||
|
|
@ -237,7 +237,7 @@ func (ac *accountCache) scanAccounts() error {
|
|||
log.Debug("Failed to reload keystore contents", "err", err)
|
||||
return err
|
||||
}
|
||||
if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 {
|
||||
if creates.Cardinality() == 0 && deletes.Cardinality() == 0 && updates.Cardinality() == 0 {
|
||||
return nil
|
||||
}
|
||||
// Create a helper method to scan the contents of the key files
|
||||
|
|
@ -272,15 +272,15 @@ func (ac *accountCache) scanAccounts() error {
|
|||
// Process all the file diffs
|
||||
start := time.Now()
|
||||
|
||||
for _, p := range creates.List() {
|
||||
for _, p := range creates.ToSlice() {
|
||||
if a := readAccount(p.(string)); a != nil {
|
||||
ac.add(*a)
|
||||
}
|
||||
}
|
||||
for _, p := range deletes.List() {
|
||||
for _, p := range deletes.ToSlice() {
|
||||
ac.deleteByFile(p.(string))
|
||||
}
|
||||
for _, p := range updates.List() {
|
||||
for _, p := range updates.ToSlice() {
|
||||
path := p.(string)
|
||||
ac.deleteByFile(path)
|
||||
if a := readAccount(path); a != nil {
|
||||
|
|
|
|||
|
|
@ -24,20 +24,20 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
set "gopkg.in/fatih/set.v0"
|
||||
)
|
||||
|
||||
// fileCache is a cache of files seen during scan of keystore.
|
||||
type fileCache struct {
|
||||
all *set.SetNonTS // Set of all files from the keystore folder
|
||||
all mapset.Set // Set of all files from the keystore folder
|
||||
lastMod time.Time // Last time instance when a file was modified
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// scan performs a new scan on the given directory, compares against the already
|
||||
// cached filenames, and returns file sets: creates, deletes, updates.
|
||||
func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) {
|
||||
func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, error) {
|
||||
t0 := time.Now()
|
||||
|
||||
// List all the failes from the keystore folder
|
||||
|
|
@ -51,8 +51,8 @@ func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Inte
|
|||
defer fc.mu.Unlock()
|
||||
|
||||
// Iterate all the files and gather their metadata
|
||||
all := set.NewNonTS()
|
||||
mods := set.NewNonTS()
|
||||
all := mapset.NewThreadUnsafeSet()
|
||||
mods := mapset.NewThreadUnsafeSet()
|
||||
|
||||
var newLastMod time.Time
|
||||
for _, fi := range files {
|
||||
|
|
@ -76,9 +76,9 @@ func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Inte
|
|||
t2 := time.Now()
|
||||
|
||||
// Update the tracked files and return the three sets
|
||||
deletes := set.Difference(fc.all, all) // Deletes = previous - current
|
||||
creates := set.Difference(all, fc.all) // Creates = current - previous
|
||||
updates := set.Difference(mods, creates) // Updates = modified - creates
|
||||
deletes := fc.all.Difference(all) // Deletes = previous - current
|
||||
creates := all.Difference(fc.all) // Creates = current - previous
|
||||
updates := mods.Difference(creates) // Updates = modified - creates
|
||||
|
||||
fc.all, fc.lastMod = all, newLastMod
|
||||
t3 := time.Now()
|
||||
|
|
|
|||
|
|
@ -28,18 +28,18 @@ package keystore
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
crand "crypto/rand"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||
"github.com/pborman/uuid"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
|
|
@ -93,7 +93,7 @@ func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string)
|
|||
|
||||
// StoreKey generates a key, encrypts with 'auth' and stores in the given directory
|
||||
func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
|
||||
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, crand.Reader, auth)
|
||||
_, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth)
|
||||
return a.Address, err
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,11 @@ func (ks keyStorePassphrase) JoinPath(filename string) string {
|
|||
// blob that can be decrypted later on.
|
||||
func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
|
||||
authArray := []byte(auth)
|
||||
salt := randentropy.GetEntropyCSPRNG(32)
|
||||
|
||||
salt := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
panic("reading from crypto/rand failed: " + err.Error())
|
||||
}
|
||||
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -124,7 +128,10 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
|
|||
encryptKey := derivedKey[:16]
|
||||
keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
|
||||
|
||||
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
|
||||
iv := make([]byte, aes.BlockSize) // 16
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic("reading from crypto/rand failed: " + err.Error())
|
||||
}
|
||||
cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ func (u URL) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// UnmarshalJSON parses url.
|
||||
func (u *URL) UnmarshalJSON(input []byte) error {
|
||||
var textUrl string
|
||||
err := json.Unmarshal(input, &textUrl)
|
||||
var textURL string
|
||||
err := json.Unmarshal(input, &textURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url, err := parseURL(textUrl)
|
||||
url, err := parseURL(textURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
96
accounts/url_test.go
Normal file
96
accounts/url_test.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestURLParsing(t *testing.T) {
|
||||
url, err := parseURL("https://ethereum.org")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if url.Scheme != "https" {
|
||||
t.Errorf("expected: %v, got: %v", "https", url.Scheme)
|
||||
}
|
||||
if url.Path != "ethereum.org" {
|
||||
t.Errorf("expected: %v, got: %v", "ethereum.org", url.Path)
|
||||
}
|
||||
|
||||
_, err = parseURL("ethereum.org")
|
||||
if err == nil {
|
||||
t.Error("expected err, got: nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLString(t *testing.T) {
|
||||
url := URL{Scheme: "https", Path: "ethereum.org"}
|
||||
if url.String() != "https://ethereum.org" {
|
||||
t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String())
|
||||
}
|
||||
|
||||
url = URL{Scheme: "", Path: "ethereum.org"}
|
||||
if url.String() != "ethereum.org" {
|
||||
t.Errorf("expected: %v, got: %v", "ethereum.org", url.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLMarshalJSON(t *testing.T) {
|
||||
url := URL{Scheme: "https", Path: "ethereum.org"}
|
||||
json, err := url.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("unexpcted error: %v", err)
|
||||
}
|
||||
if string(json) != "\"https://ethereum.org\"" {
|
||||
t.Errorf("expected: %v, got: %v", "\"https://ethereum.org\"", string(json))
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLUnmarshalJSON(t *testing.T) {
|
||||
url := &URL{}
|
||||
err := url.UnmarshalJSON([]byte("\"https://ethereum.org\""))
|
||||
if err != nil {
|
||||
t.Errorf("unexpcted error: %v", err)
|
||||
}
|
||||
if url.Scheme != "https" {
|
||||
t.Errorf("expected: %v, got: %v", "https", url.Scheme)
|
||||
}
|
||||
if url.Path != "ethereum.org" {
|
||||
t.Errorf("expected: %v, got: %v", "https", url.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLComparison(t *testing.T) {
|
||||
tests := []struct {
|
||||
urlA URL
|
||||
urlB URL
|
||||
expect int
|
||||
}{
|
||||
{URL{"https", "ethereum.org"}, URL{"https", "ethereum.org"}, 0},
|
||||
{URL{"http", "ethereum.org"}, URL{"https", "ethereum.org"}, -1},
|
||||
{URL{"https", "ethereum.org/a"}, URL{"https", "ethereum.org"}, 1},
|
||||
{URL{"https", "abc.org"}, URL{"https", "ethereum.org"}, -1},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
result := tt.urlA.Cmp(tt.urlB)
|
||||
if result != tt.expect {
|
||||
t.Errorf("test %d: cmp mismatch: expected: %d, got: %d", i, tt.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
184
build/ci.go
184
build/ci.go
|
|
@ -26,7 +26,7 @@ Available commands are:
|
|||
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
|
||||
test [ -coverage ] [ packages... ] -- runs the tests
|
||||
lint -- runs certain pre-selected linters
|
||||
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
|
||||
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artifacts
|
||||
importkeys -- imports signing keys from env
|
||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||
nsis -- creates a Windows NSIS installer
|
||||
|
|
@ -59,6 +59,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/internal/build"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
sv "github.com/ethereum/go-ethereum/swarm/version"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -77,52 +79,81 @@ var (
|
|||
executablePath("geth"),
|
||||
executablePath("puppeth"),
|
||||
executablePath("rlpdump"),
|
||||
executablePath("swarm"),
|
||||
executablePath("wnode"),
|
||||
}
|
||||
|
||||
// Files that end up in the swarm*.zip archive.
|
||||
swarmArchiveFiles = []string{
|
||||
"COPYING",
|
||||
executablePath("swarm"),
|
||||
}
|
||||
|
||||
// A debian package is created for all executables listed here.
|
||||
debExecutables = []debExecutable{
|
||||
{
|
||||
Name: "abigen",
|
||||
BinaryName: "abigen",
|
||||
Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.",
|
||||
},
|
||||
{
|
||||
Name: "bootnode",
|
||||
BinaryName: "bootnode",
|
||||
Description: "Ethereum bootnode.",
|
||||
},
|
||||
{
|
||||
Name: "evm",
|
||||
BinaryName: "evm",
|
||||
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
|
||||
},
|
||||
{
|
||||
Name: "geth",
|
||||
BinaryName: "geth",
|
||||
Description: "Ethereum CLI client.",
|
||||
},
|
||||
{
|
||||
Name: "puppeth",
|
||||
BinaryName: "puppeth",
|
||||
Description: "Ethereum private network manager.",
|
||||
},
|
||||
{
|
||||
Name: "rlpdump",
|
||||
BinaryName: "rlpdump",
|
||||
Description: "Developer utility tool that prints RLP structures.",
|
||||
},
|
||||
{
|
||||
Name: "swarm",
|
||||
Description: "Ethereum Swarm daemon and tools",
|
||||
},
|
||||
{
|
||||
Name: "wnode",
|
||||
BinaryName: "wnode",
|
||||
Description: "Ethereum Whisper diagnostic tool",
|
||||
},
|
||||
}
|
||||
|
||||
// A debian package is created for all executables listed here.
|
||||
debSwarmExecutables = []debExecutable{
|
||||
{
|
||||
BinaryName: "swarm",
|
||||
PackageName: "ethereum-swarm",
|
||||
Description: "Ethereum Swarm daemon and tools",
|
||||
},
|
||||
}
|
||||
|
||||
debEthereum = debPackage{
|
||||
Name: "ethereum",
|
||||
Version: params.Version,
|
||||
Executables: debExecutables,
|
||||
}
|
||||
|
||||
debSwarm = debPackage{
|
||||
Name: "ethereum-swarm",
|
||||
Version: sv.Version,
|
||||
Executables: debSwarmExecutables,
|
||||
}
|
||||
|
||||
// Debian meta packages to build and push to Ubuntu PPA
|
||||
debPackages = []debPackage{
|
||||
debSwarm,
|
||||
debEthereum,
|
||||
}
|
||||
|
||||
// Distros for which packages are created.
|
||||
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
||||
// Note: wily is unsupported because it was officially deprecated on lanchpad.
|
||||
// Note: yakkety is unsupported because it was officially deprecated on lanchpad.
|
||||
// Note: zesty is unsupported because it was officially deprecated on lanchpad.
|
||||
debDistros = []string{"trusty", "xenial", "artful", "bionic"}
|
||||
// Note: artful is unsupported because it was officially deprecated on lanchpad.
|
||||
debDistros = []string{"trusty", "xenial", "bionic", "cosmic"}
|
||||
)
|
||||
|
||||
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
||||
|
|
@ -350,7 +381,6 @@ func doLint(cmdline []string) {
|
|||
}
|
||||
|
||||
// Release Packaging
|
||||
|
||||
func doArchive(cmdline []string) {
|
||||
var (
|
||||
arch = flag.String("arch", runtime.GOARCH, "Architecture cross packaging")
|
||||
|
|
@ -371,9 +401,13 @@ func doArchive(cmdline []string) {
|
|||
|
||||
var (
|
||||
env = build.Env()
|
||||
base = archiveBasename(*arch, env)
|
||||
geth = "geth-" + base + ext
|
||||
alltools = "geth-alltools-" + base + ext
|
||||
|
||||
basegeth = archiveBasename(*arch, params.ArchiveVersion(env.Commit))
|
||||
geth = "geth-" + basegeth + ext
|
||||
alltools = "geth-alltools-" + basegeth + ext
|
||||
|
||||
baseswarm = archiveBasename(*arch, sv.ArchiveVersion(env.Commit))
|
||||
swarm = "swarm-" + baseswarm + ext
|
||||
)
|
||||
maybeSkipArchive(env)
|
||||
if err := build.WriteArchive(geth, gethArchiveFiles); err != nil {
|
||||
|
|
@ -382,14 +416,17 @@ func doArchive(cmdline []string) {
|
|||
if err := build.WriteArchive(alltools, allToolsArchiveFiles); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, archive := range []string{geth, alltools} {
|
||||
if err := build.WriteArchive(swarm, swarmArchiveFiles); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, archive := range []string{geth, alltools, swarm} {
|
||||
if err := archiveUpload(archive, *upload, *signer); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func archiveBasename(arch string, env build.Environment) string {
|
||||
func archiveBasename(arch string, archiveVersion string) string {
|
||||
platform := runtime.GOOS + "-" + arch
|
||||
if arch == "arm" {
|
||||
platform += os.Getenv("GOARM")
|
||||
|
|
@ -400,18 +437,7 @@ func archiveBasename(arch string, env build.Environment) string {
|
|||
if arch == "ios" {
|
||||
platform = "ios-all"
|
||||
}
|
||||
return platform + "-" + archiveVersion(env)
|
||||
}
|
||||
|
||||
func archiveVersion(env build.Environment) string {
|
||||
version := build.VERSION()
|
||||
if isUnstableBuild(env) {
|
||||
version += "-unstable"
|
||||
}
|
||||
if env.Commit != "" {
|
||||
version += "-" + env.Commit[:8]
|
||||
}
|
||||
return version
|
||||
return platform + "-" + archiveVersion
|
||||
}
|
||||
|
||||
func archiveUpload(archive string, blobstore string, signer string) error {
|
||||
|
|
@ -461,7 +487,6 @@ func maybeSkipArchive(env build.Environment) {
|
|||
}
|
||||
|
||||
// Debian Packaging
|
||||
|
||||
func doDebianSource(cmdline []string) {
|
||||
var (
|
||||
signer = flag.String("signer", "", `Signing key name, also used as package author`)
|
||||
|
|
@ -485,9 +510,10 @@ func doDebianSource(cmdline []string) {
|
|||
build.MustRun(gpg)
|
||||
}
|
||||
|
||||
// Create the packages.
|
||||
// Create Debian packages and upload them
|
||||
for _, pkg := range debPackages {
|
||||
for _, distro := range debDistros {
|
||||
meta := newDebMetadata(distro, *signer, env, now)
|
||||
meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
||||
pkgdir := stageDebianSource(*workdir, meta)
|
||||
debuild := exec.Command("debuild", "-S", "-sa", "-us", "-uc")
|
||||
debuild.Dir = pkgdir
|
||||
|
|
@ -502,6 +528,7 @@ func doDebianSource(cmdline []string) {
|
|||
build.MustRunCommand("dput", *upload, changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeWorkdir(wdflag string) string {
|
||||
|
|
@ -524,9 +551,17 @@ func isUnstableBuild(env build.Environment) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
type debPackage struct {
|
||||
Name string // the name of the Debian package to produce, e.g. "ethereum", or "ethereum-swarm"
|
||||
Version string // the clean version of the debPackage, e.g. 1.8.12 or 0.3.0, without any metadata
|
||||
Executables []debExecutable // executables to be included in the package
|
||||
}
|
||||
|
||||
type debMetadata struct {
|
||||
Env build.Environment
|
||||
|
||||
PackageName string
|
||||
|
||||
// go-ethereum version being built. Note that this
|
||||
// is not the debian package version. The package version
|
||||
// is constructed by VersionString.
|
||||
|
|
@ -538,21 +573,33 @@ type debMetadata struct {
|
|||
}
|
||||
|
||||
type debExecutable struct {
|
||||
Name, Description string
|
||||
PackageName string
|
||||
BinaryName string
|
||||
Description string
|
||||
}
|
||||
|
||||
func newDebMetadata(distro, author string, env build.Environment, t time.Time) debMetadata {
|
||||
// Package returns the name of the package if present, or
|
||||
// fallbacks to BinaryName
|
||||
func (d debExecutable) Package() string {
|
||||
if d.PackageName != "" {
|
||||
return d.PackageName
|
||||
}
|
||||
return d.BinaryName
|
||||
}
|
||||
|
||||
func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
|
||||
if author == "" {
|
||||
// No signing key, use default author.
|
||||
author = "Ethereum Builds <fjl@ethereum.org>"
|
||||
}
|
||||
return debMetadata{
|
||||
PackageName: name,
|
||||
Env: env,
|
||||
Author: author,
|
||||
Distro: distro,
|
||||
Version: build.VERSION(),
|
||||
Version: version,
|
||||
Time: t.Format(time.RFC1123Z),
|
||||
Executables: debExecutables,
|
||||
Executables: exes,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -560,9 +607,9 @@ func newDebMetadata(distro, author string, env build.Environment, t time.Time) d
|
|||
// on all executable packages.
|
||||
func (meta debMetadata) Name() string {
|
||||
if isUnstableBuild(meta.Env) {
|
||||
return "ethereum-unstable"
|
||||
return meta.PackageName + "-unstable"
|
||||
}
|
||||
return "ethereum"
|
||||
return meta.PackageName
|
||||
}
|
||||
|
||||
// VersionString returns the debian version of the packages.
|
||||
|
|
@ -589,9 +636,20 @@ func (meta debMetadata) ExeList() string {
|
|||
// ExeName returns the package name of an executable package.
|
||||
func (meta debMetadata) ExeName(exe debExecutable) string {
|
||||
if isUnstableBuild(meta.Env) {
|
||||
return exe.Name + "-unstable"
|
||||
return exe.Package() + "-unstable"
|
||||
}
|
||||
return exe.Name
|
||||
return exe.Package()
|
||||
}
|
||||
|
||||
// EthereumSwarmPackageName returns the name of the swarm package based on
|
||||
// environment, e.g. "ethereum-swarm-unstable", or "ethereum-swarm".
|
||||
// This is needed so that we make sure that "ethereum" package,
|
||||
// depends on and installs "ethereum-swarm"
|
||||
func (meta debMetadata) EthereumSwarmPackageName() string {
|
||||
if isUnstableBuild(meta.Env) {
|
||||
return debSwarm.Name + "-unstable"
|
||||
}
|
||||
return debSwarm.Name
|
||||
}
|
||||
|
||||
// ExeConflicts returns the content of the Conflicts field
|
||||
|
|
@ -606,7 +664,7 @@ func (meta debMetadata) ExeConflicts(exe debExecutable) string {
|
|||
// be preferred and the conflicting files should be handled via
|
||||
// alternates. We might do this eventually but using a conflict is
|
||||
// easier now.
|
||||
return "ethereum, " + exe.Name
|
||||
return "ethereum, " + exe.Package()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
@ -623,24 +681,23 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) {
|
|||
|
||||
// Put the debian build files in place.
|
||||
debian := filepath.Join(pkgdir, "debian")
|
||||
build.Render("build/deb.rules", filepath.Join(debian, "rules"), 0755, meta)
|
||||
build.Render("build/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta)
|
||||
build.Render("build/deb.control", filepath.Join(debian, "control"), 0644, meta)
|
||||
build.Render("build/deb.copyright", filepath.Join(debian, "copyright"), 0644, meta)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.rules", filepath.Join(debian, "rules"), 0755, meta)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.changelog", filepath.Join(debian, "changelog"), 0644, meta)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.control", filepath.Join(debian, "control"), 0644, meta)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.copyright", filepath.Join(debian, "copyright"), 0644, meta)
|
||||
build.RenderString("8\n", filepath.Join(debian, "compat"), 0644, meta)
|
||||
build.RenderString("3.0 (native)\n", filepath.Join(debian, "source/format"), 0644, meta)
|
||||
for _, exe := range meta.Executables {
|
||||
install := filepath.Join(debian, meta.ExeName(exe)+".install")
|
||||
docs := filepath.Join(debian, meta.ExeName(exe)+".docs")
|
||||
build.Render("build/deb.install", install, 0644, exe)
|
||||
build.Render("build/deb.docs", docs, 0644, exe)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.install", install, 0644, exe)
|
||||
build.Render("build/deb/"+meta.PackageName+"/deb.docs", docs, 0644, exe)
|
||||
}
|
||||
|
||||
return pkgdir
|
||||
}
|
||||
|
||||
// Windows installer
|
||||
|
||||
func doWindowsInstaller(cmdline []string) {
|
||||
// Parse the flags and make skip installer generation on PRs
|
||||
var (
|
||||
|
|
@ -690,11 +747,11 @@ func doWindowsInstaller(cmdline []string) {
|
|||
// Build the installer. This assumes that all the needed files have been previously
|
||||
// built (don't mix building and packaging to keep cross compilation complexity to a
|
||||
// minimum).
|
||||
version := strings.Split(build.VERSION(), ".")
|
||||
version := strings.Split(params.Version, ".")
|
||||
if env.Commit != "" {
|
||||
version[2] += "-" + env.Commit[:8]
|
||||
}
|
||||
installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, env) + ".exe")
|
||||
installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + ".exe")
|
||||
build.MustRunCommand("makensis.exe",
|
||||
"/DOUTPUTFILE="+installer,
|
||||
"/DMAJORVERSION="+version[0],
|
||||
|
|
@ -746,7 +803,7 @@ func doAndroidArchive(cmdline []string) {
|
|||
maybeSkipArchive(env)
|
||||
|
||||
// Sign and upload the archive to Azure
|
||||
archive := "geth-" + archiveBasename("android", env) + ".aar"
|
||||
archive := "geth-" + archiveBasename("android", params.ArchiveVersion(env.Commit)) + ".aar"
|
||||
os.Rename("geth.aar", archive)
|
||||
|
||||
if err := archiveUpload(archive, *upload, *signer); err != nil {
|
||||
|
|
@ -831,7 +888,7 @@ func newMavenMetadata(env build.Environment) mavenMetadata {
|
|||
}
|
||||
}
|
||||
// Render the version and package strings
|
||||
version := build.VERSION()
|
||||
version := params.Version
|
||||
if isUnstableBuild(env) {
|
||||
version += "-SNAPSHOT"
|
||||
}
|
||||
|
|
@ -866,7 +923,7 @@ func doXCodeFramework(cmdline []string) {
|
|||
build.MustRun(bind)
|
||||
return
|
||||
}
|
||||
archive := "geth-" + archiveBasename("ios", env)
|
||||
archive := "geth-" + archiveBasename("ios", params.ArchiveVersion(env.Commit))
|
||||
if err := os.Mkdir(archive, os.ModePerm); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
@ -922,7 +979,7 @@ func newPodMetadata(env build.Environment, archive string) podMetadata {
|
|||
}
|
||||
}
|
||||
}
|
||||
version := build.VERSION()
|
||||
version := params.Version
|
||||
if isUnstableBuild(env) {
|
||||
version += "-unstable." + env.Buildnum
|
||||
}
|
||||
|
|
@ -1018,23 +1075,14 @@ func doPurge(cmdline []string) {
|
|||
}
|
||||
for i := 0; i < len(blobs); i++ {
|
||||
for j := i + 1; j < len(blobs); j++ {
|
||||
iTime, err := time.Parse(time.RFC1123, blobs[i].Properties.LastModified)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
jTime, err := time.Parse(time.RFC1123, blobs[j].Properties.LastModified)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if iTime.After(jTime) {
|
||||
if blobs[i].Properties.LastModified.After(blobs[j].Properties.LastModified) {
|
||||
blobs[i], blobs[j] = blobs[j], blobs[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filter out all archives more recent that the given threshold
|
||||
for i, blob := range blobs {
|
||||
timestamp, _ := time.Parse(time.RFC1123, blob.Properties.LastModified)
|
||||
if time.Since(timestamp) < time.Duration(*limit)*24*time.Hour {
|
||||
if time.Since(blob.Properties.LastModified) < time.Duration(*limit)*24*time.Hour {
|
||||
blobs = blobs[:i]
|
||||
break
|
||||
}
|
||||
|
|
|
|||
19
build/clean_go_build_cache.sh
Executable file
19
build/clean_go_build_cache.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Cleaning the Go cache only makes sense if we actually have Go installed... or
|
||||
# if Go is actually callable. This does not hold true during deb packaging, so
|
||||
# we need an explicit check to avoid build failures.
|
||||
if ! command -v go > /dev/null; then
|
||||
exit
|
||||
fi
|
||||
|
||||
version_gt() {
|
||||
test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"
|
||||
}
|
||||
|
||||
golang_version=$(go version |cut -d' ' -f3 |sed 's/go//')
|
||||
|
||||
# Clean go build cache when go version is greater than or equal to 1.10
|
||||
if !(version_gt 1.10 $golang_version); then
|
||||
go clean -cache
|
||||
fi
|
||||
|
|
@ -1 +0,0 @@
|
|||
build/bin/{{.Name}} usr/bin
|
||||
19
build/deb/ethereum-swarm/deb.control
Normal file
19
build/deb/ethereum-swarm/deb.control
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Source: {{.Name}}
|
||||
Section: science
|
||||
Priority: extra
|
||||
Maintainer: {{.Author}}
|
||||
Build-Depends: debhelper (>= 8.0.0), golang-1.10
|
||||
Standards-Version: 3.9.5
|
||||
Homepage: https://ethereum.org
|
||||
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
||||
Vcs-Browser: https://github.com/ethereum/go-ethereum
|
||||
|
||||
{{range .Executables}}
|
||||
Package: {{$.ExeName .}}
|
||||
Conflicts: {{$.ExeConflicts .}}
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Built-Using: ${misc:Built-Using}
|
||||
Description: {{.Description}}
|
||||
{{.Description}}
|
||||
{{end}}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Copyright 2016 The go-ethereum Authors
|
||||
Copyright 2018 The go-ethereum Authors
|
||||
|
||||
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
|
||||
1
build/deb/ethereum-swarm/deb.install
Normal file
1
build/deb/ethereum-swarm/deb.install
Normal file
|
|
@ -0,0 +1 @@
|
|||
build/bin/{{.BinaryName}} usr/bin
|
||||
5
build/deb/ethereum/deb.changelog
Normal file
5
build/deb/ethereum/deb.changelog
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{{.Name}} ({{.VersionString}}) {{.Distro}}; urgency=low
|
||||
|
||||
* git build of {{.Env.Commit}}
|
||||
|
||||
-- {{.Author}} {{.Time}}
|
||||
|
|
@ -10,9 +10,9 @@ Vcs-Browser: https://github.com/ethereum/go-ethereum
|
|||
|
||||
Package: {{.Name}}
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, {{.ExeList}}
|
||||
Description: Meta-package to install geth and other tools
|
||||
Meta-package to install geth and other tools
|
||||
Depends: ${misc:Depends}, {{.EthereumSwarmPackageName}}, {{.ExeList}}
|
||||
Description: Meta-package to install geth, swarm, and other tools
|
||||
Meta-package to install geth, swarm and other tools
|
||||
|
||||
{{range .Executables}}
|
||||
Package: {{$.ExeName .}}
|
||||
14
build/deb/ethereum/deb.copyright
Normal file
14
build/deb/ethereum/deb.copyright
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Copyright 2018 The go-ethereum Authors
|
||||
|
||||
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/>.
|
||||
1
build/deb/ethereum/deb.docs
Normal file
1
build/deb/ethereum/deb.docs
Normal file
|
|
@ -0,0 +1 @@
|
|||
AUTHORS
|
||||
1
build/deb/ethereum/deb.install
Normal file
1
build/deb/ethereum/deb.install
Normal file
|
|
@ -0,0 +1 @@
|
|||
build/bin/{{.BinaryName}} usr/bin
|
||||
13
build/deb/ethereum/deb.rules
Normal file
13
build/deb/ethereum/deb.rules
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
override_dh_auto_build:
|
||||
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
|
@ -415,7 +415,7 @@ func signer(c *cli.Context) error {
|
|||
|
||||
// start http server
|
||||
httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
|
||||
listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"account"}, cors, vhosts)
|
||||
listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"account"}, cors, vhosts, rpc.DefaultHTTPTimeouts)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not start RPC api: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,6 @@ func compileCmd(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(bin)
|
||||
fmt.Fprintln(ctx.App.Writer, bin)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,6 @@ func disasmCmd(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
code := strings.TrimSpace(string(in[:]))
|
||||
fmt.Printf("%v\n", code)
|
||||
fmt.Fprintf(ctx.App.Writer, "%v\n", code)
|
||||
return asm.PrintDisassembled(code)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,11 @@ func Compile(fn string, src []byte, debug bool) (string, error) {
|
|||
bin, compileErrors := compiler.Compile()
|
||||
if len(compileErrors) > 0 {
|
||||
// report errors
|
||||
errs := ""
|
||||
for _, err := range compileErrors {
|
||||
fmt.Printf("%s:%v\n", fn, err)
|
||||
errs += fmt.Sprintf("%s:%v\n", fn, err)
|
||||
}
|
||||
return "", errors.New("compiling failed")
|
||||
return "", errors.New(errs + "compiling failed\n")
|
||||
}
|
||||
return bin, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,13 +128,13 @@ func runCmd(ctx *cli.Context) error {
|
|||
if ctx.GlobalString(CodeFileFlag.Name) == "-" {
|
||||
//Try reading from stdin
|
||||
if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil {
|
||||
fmt.Printf("Could not load code from stdin: %v\n", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "Could not load code from stdin: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
// Codefile with hex assembly
|
||||
if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil {
|
||||
fmt.Printf("Could not load code from file: %v\n", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "Could not load code from file: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
@ -172,11 +172,11 @@ func runCmd(ctx *cli.Context) error {
|
|||
if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" {
|
||||
f, err := os.Create(cpuProfilePath)
|
||||
if err != nil {
|
||||
fmt.Println("could not create CPU profile: ", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "could not create CPU profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
fmt.Println("could not start CPU profile: ", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "could not start CPU profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
|
|
@ -200,17 +200,17 @@ func runCmd(ctx *cli.Context) error {
|
|||
|
||||
if ctx.GlobalBool(DumpFlag.Name) {
|
||||
statedb.IntermediateRoot(true)
|
||||
fmt.Println(string(statedb.Dump()))
|
||||
fmt.Fprintln(ctx.App.Writer, string(statedb.Dump()))
|
||||
}
|
||||
|
||||
if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" {
|
||||
f, err := os.Create(memProfilePath)
|
||||
if err != nil {
|
||||
fmt.Println("could not create memory profile: ", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "could not create memory profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
fmt.Println("could not write memory profile: ", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "could not create memory profile: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
f.Close()
|
||||
|
|
@ -218,17 +218,17 @@ func runCmd(ctx *cli.Context) error {
|
|||
|
||||
if ctx.GlobalBool(DebugFlag.Name) {
|
||||
if debugLogger != nil {
|
||||
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
||||
vm.WriteTrace(os.Stderr, debugLogger.StructLogs())
|
||||
fmt.Fprintln(ctx.App.ErrWriter, "#### TRACE ####")
|
||||
vm.WriteTrace(ctx.App.ErrWriter, debugLogger.StructLogs())
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "#### LOGS ####")
|
||||
vm.WriteLogs(os.Stderr, statedb.Logs())
|
||||
fmt.Fprintln(ctx.App.ErrWriter, "#### LOGS ####")
|
||||
vm.WriteLogs(ctx.App.ErrWriter, statedb.Logs())
|
||||
}
|
||||
|
||||
if ctx.GlobalBool(StatDumpFlag.Name) {
|
||||
var mem goruntime.MemStats
|
||||
goruntime.ReadMemStats(&mem)
|
||||
fmt.Fprintf(os.Stderr, `evm execution time: %v
|
||||
fmt.Fprintf(ctx.App.ErrWriter, `evm execution time: %v
|
||||
heap objects: %d
|
||||
allocations: %d
|
||||
total allocations: %d
|
||||
|
|
@ -238,9 +238,9 @@ Gas used: %d
|
|||
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
|
||||
}
|
||||
if tracer == nil {
|
||||
fmt.Printf("0x%x\n", ret)
|
||||
fmt.Fprintf(ctx.App.Writer, "0x%x\n", ret)
|
||||
if err != nil {
|
||||
fmt.Printf(" error: %v\n", err)
|
||||
fmt.Fprintf(ctx.App.ErrWriter, " error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ func stateTestCmd(ctx *cli.Context) error {
|
|||
}
|
||||
// print state root for evmlab tracing (already committed above, so no need to delete objects again
|
||||
if ctx.GlobalBool(MachineFlag.Name) && state != nil {
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
|
||||
fmt.Fprintf(ctx.App.ErrWriter, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
|
||||
}
|
||||
|
||||
results = append(results, *result)
|
||||
|
|
@ -115,13 +115,13 @@ func stateTestCmd(ctx *cli.Context) error {
|
|||
// Print any structured logs collected
|
||||
if ctx.GlobalBool(DebugFlag.Name) {
|
||||
if debugger != nil {
|
||||
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
||||
vm.WriteTrace(os.Stderr, debugger.StructLogs())
|
||||
fmt.Fprintln(ctx.App.ErrWriter, "#### TRACE ####")
|
||||
vm.WriteTrace(ctx.App.ErrWriter, debugger.StructLogs())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out, _ := json.MarshalIndent(results, "", " ")
|
||||
fmt.Println(string(out))
|
||||
fmt.Fprintln(ctx.App.Writer, string(out))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
|
|||
// Assemble the raw devp2p protocol stack
|
||||
stack, err := node.New(&node.Config{
|
||||
Name: "geth",
|
||||
Version: params.Version,
|
||||
Version: params.VersionWithMeta,
|
||||
DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"),
|
||||
P2P: p2p.Config{
|
||||
NAT: nat.Any(),
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func reportBug(ctx *cli.Context) error {
|
|||
|
||||
fmt.Fprintln(&buff, "#### System information")
|
||||
fmt.Fprintln(&buff)
|
||||
fmt.Fprintln(&buff, "Version:", params.Version)
|
||||
fmt.Fprintln(&buff, "Version:", params.VersionWithMeta)
|
||||
fmt.Fprintln(&buff, "Go Version:", runtime.Version())
|
||||
fmt.Fprintln(&buff, "OS:", runtime.GOOS)
|
||||
printOSDetails(&buff)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ processing will proceed even if an individual RLP-file import failure occurs.`,
|
|||
Requires a first argument of the file to write to.
|
||||
Optional second and third arguments control the first and
|
||||
last block to write. In this mode, the file will be appended
|
||||
if already existing.`,
|
||||
if already existing. If the file ends with .gz, the output will
|
||||
be gzipped.`,
|
||||
}
|
||||
importPreimagesCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(importPreimages),
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestConsoleWelcome(t *testing.T) {
|
|||
geth.SetTemplateFunc("goos", func() string { return runtime.GOOS })
|
||||
geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
|
||||
geth.SetTemplateFunc("gover", runtime.Version)
|
||||
geth.SetTemplateFunc("gethver", func() string { return params.Version })
|
||||
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta })
|
||||
geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
||||
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
|||
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
|
||||
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
|
||||
attach.SetTemplateFunc("gover", runtime.Version)
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.Version })
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta })
|
||||
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
||||
attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||
|
|
|
|||
|
|
@ -202,10 +202,15 @@ func init() {
|
|||
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
if err := debug.Setup(ctx); err != nil {
|
||||
|
||||
logdir := ""
|
||||
if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
|
||||
logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs")
|
||||
}
|
||||
if err := debug.Setup(ctx, logdir); err != nil {
|
||||
return err
|
||||
}
|
||||
// Cap the cache allowance and tune the garbage colelctor
|
||||
// Cap the cache allowance and tune the garbage collector
|
||||
var mem gosigar.Mem
|
||||
if err := mem.Get(); err == nil {
|
||||
allowance := int(mem.Total / 1024 / 1024 / 3)
|
||||
|
|
@ -249,6 +254,9 @@ func main() {
|
|||
// It creates a default node based on the command line arguments and runs it in
|
||||
// blocking mode, waiting for it to be shut down.
|
||||
func geth(ctx *cli.Context) error {
|
||||
if args := ctx.Args(); len(args) > 0 {
|
||||
return fmt.Errorf("invalid command: %q", args[0])
|
||||
}
|
||||
node := makeFullNode(ctx)
|
||||
startNode(ctx, node)
|
||||
node.Wait()
|
||||
|
|
@ -303,11 +311,11 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
|||
status, _ := event.Wallet.Status()
|
||||
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
|
||||
|
||||
derivationPath := accounts.DefaultBaseDerivationPath
|
||||
if event.Wallet.URL().Scheme == "ledger" {
|
||||
event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
|
||||
} else {
|
||||
event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
||||
derivationPath = accounts.DefaultLedgerBaseDerivationPath
|
||||
}
|
||||
event.Wallet.SelfDerive(derivationPath, stateReader)
|
||||
|
||||
case accounts.WalletDropped:
|
||||
log.Info("Old wallet dropped", "url", event.Wallet.URL())
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ func makedag(ctx *cli.Context) error {
|
|||
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", params.Version)
|
||||
fmt.Println("Version:", params.VersionWithMeta)
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit:", gitCommit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,12 +185,12 @@ func resolveMetric(metrics map[string]interface{}, pattern string, path string)
|
|||
parts := strings.SplitN(pattern, "/", 2)
|
||||
if len(parts) > 1 {
|
||||
for _, variation := range strings.Split(parts[0], ",") {
|
||||
if submetrics, ok := metrics[variation].(map[string]interface{}); !ok {
|
||||
submetrics, ok := metrics[variation].(map[string]interface{})
|
||||
if !ok {
|
||||
utils.Fatalf("Failed to retrieve system metrics: %s", path+variation)
|
||||
return nil
|
||||
} else {
|
||||
results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...)
|
||||
}
|
||||
results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ var AppHelpFlagGroups = []flagGroup{
|
|||
utils.LightKDFFlag,
|
||||
},
|
||||
},
|
||||
{Name: "DEVELOPER CHAIN",
|
||||
{
|
||||
Name: "DEVELOPER CHAIN",
|
||||
Flags: []cli.Flag{
|
||||
utils.DeveloperFlag,
|
||||
utils.DeveloperPeriodFlag,
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ func (info *ethstatsInfos) Report() map[string]string {
|
|||
"Website address": info.host,
|
||||
"Website listener port": strconv.Itoa(info.port),
|
||||
"Login secret": info.secret,
|
||||
"Banned addresses": fmt.Sprintf("%v", info.banned),
|
||||
"Banned addresses": strings.Join(info.banned, "\n"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error)
|
|||
|
||||
// Container available, retrieve its node ID and its genesis json
|
||||
var out []byte
|
||||
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.id attach", network, kind)); err != nil {
|
||||
if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.id --cache=16 attach", network, kind)); err != nil {
|
||||
return nil, ErrServiceUnreachable
|
||||
}
|
||||
id := bytes.Trim(bytes.TrimSpace(out), "\"")
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ func (stats serverStats) render() {
|
|||
|
||||
table.SetHeader([]string{"Server", "Address", "Service", "Config", "Value"})
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetColWidth(100)
|
||||
table.SetColWidth(40)
|
||||
|
||||
// Find the longest lines for all columns for the hacked separator
|
||||
separator := make([]string, 5)
|
||||
|
|
@ -222,8 +222,10 @@ func (stats serverStats) render() {
|
|||
if len(config) > len(separator[3]) {
|
||||
separator[3] = strings.Repeat("-", len(config))
|
||||
}
|
||||
if len(value) > len(separator[4]) {
|
||||
separator[4] = strings.Repeat("-", len(value))
|
||||
for _, val := range strings.Split(value, "\n") {
|
||||
if len(val) > len(separator[4]) {
|
||||
separator[4] = strings.Repeat("-", len(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -263,13 +265,17 @@ func (stats serverStats) render() {
|
|||
sort.Strings(configs)
|
||||
|
||||
for k, config := range configs {
|
||||
for l, value := range strings.Split(stats[server].services[service][config], "\n") {
|
||||
switch {
|
||||
case j == 0 && k == 0:
|
||||
table.Append([]string{server, stats[server].address, service, config, stats[server].services[service][config]})
|
||||
case k == 0:
|
||||
table.Append([]string{"", "", service, config, stats[server].services[service][config]})
|
||||
case j == 0 && k == 0 && l == 0:
|
||||
table.Append([]string{server, stats[server].address, service, config, value})
|
||||
case k == 0 && l == 0:
|
||||
table.Append([]string{"", "", service, config, value})
|
||||
case l == 0:
|
||||
table.Append([]string{"", "", "", config, value})
|
||||
default:
|
||||
table.Append([]string{"", "", "", config, stats[server].services[service][config]})
|
||||
table.Append([]string{"", "", "", "", value})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ import (
|
|||
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
||||
)
|
||||
|
||||
const SWARM_VERSION = "0.3"
|
||||
|
||||
var (
|
||||
//flag definition for the dumpconfig command
|
||||
DumpConfigCommand = cli.Command{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build linux darwin freebsd
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ func hash(ctx *cli.Context) {
|
|||
|
||||
stat, _ := f.Stat()
|
||||
fileStore := storage.NewFileStore(storage.NewMapChunkStore(), storage.NewFileStoreParams())
|
||||
addr, _, err := fileStore.Store(f, stat.Size(), false)
|
||||
addr, _, err := fileStore.Store(context.TODO(), f, stat.Size(), false)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v\n", err)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -39,10 +39,11 @@ import (
|
|||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/swarm"
|
||||
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
|
||||
"github.com/ethereum/go-ethereum/swarm/tracing"
|
||||
sv "github.com/ethereum/go-ethereum/swarm/version"
|
||||
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
|
@ -143,7 +144,7 @@ var (
|
|||
}
|
||||
SwarmWantManifestFlag = cli.BoolTFlag{
|
||||
Name: "manifest",
|
||||
Usage: "Automatic manifest upload",
|
||||
Usage: "Automatic manifest upload (default true)",
|
||||
}
|
||||
SwarmUploadDefaultPath = cli.StringFlag{
|
||||
Name: "defaultpath",
|
||||
|
|
@ -155,7 +156,7 @@ var (
|
|||
}
|
||||
SwarmUploadMimeType = cli.StringFlag{
|
||||
Name: "mime",
|
||||
Usage: "force mime type",
|
||||
Usage: "Manually specify MIME type",
|
||||
}
|
||||
SwarmEncryptedFlag = cli.BoolFlag{
|
||||
Name: "encrypt",
|
||||
|
|
@ -181,6 +182,18 @@ var (
|
|||
Usage: "Number of recent chunks cached in memory (default 5000)",
|
||||
EnvVar: SWARM_ENV_STORE_CACHE_CAPACITY,
|
||||
}
|
||||
SwarmResourceMultihashFlag = cli.BoolFlag{
|
||||
Name: "multihash",
|
||||
Usage: "Determines how to interpret data for a resource update. If not present, data will be interpreted as raw, literal data that will be included in the resource",
|
||||
}
|
||||
SwarmResourceNameFlag = cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "User-defined name for the new resource",
|
||||
}
|
||||
SwarmResourceDataOnCreateFlag = cli.StringFlag{
|
||||
Name: "data",
|
||||
Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x",
|
||||
}
|
||||
)
|
||||
|
||||
//declare a few constant error messages, useful for later error check comparisons in test
|
||||
|
|
@ -189,12 +202,21 @@ var (
|
|||
SWARM_ERR_SWAP_SET_NO_API = "SWAP is enabled but --swap-api is not set"
|
||||
)
|
||||
|
||||
// this help command gets added to any subcommand that does not define it explicitly
|
||||
var defaultSubcommandHelp = cli.Command{
|
||||
Action: func(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "", 1) },
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "help",
|
||||
Usage: "shows this help",
|
||||
Hidden: true,
|
||||
}
|
||||
|
||||
var defaultNodeConfig = node.DefaultConfig
|
||||
|
||||
// This init function sets defaults so cmd/swarm can run alongside geth.
|
||||
func init() {
|
||||
defaultNodeConfig.Name = clientIdentifier
|
||||
defaultNodeConfig.Version = params.VersionWithCommit(gitCommit)
|
||||
defaultNodeConfig.Version = sv.VersionWithCommit(gitCommit)
|
||||
defaultNodeConfig.P2P.ListenAddr = ":30399"
|
||||
defaultNodeConfig.IPCPath = "bzzd.ipc"
|
||||
// Set flag defaults for --help display.
|
||||
|
|
@ -225,6 +247,41 @@ func init() {
|
|||
Flags: []cli.Flag{SwarmEncryptedFlag},
|
||||
Description: "uploads a file or directory to swarm using the HTTP API and prints the root hash",
|
||||
},
|
||||
{
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "resource",
|
||||
Usage: "(Advanced) Create and update Mutable Resources",
|
||||
ArgsUsage: "<create|update|info>",
|
||||
Description: "Works with Mutable Resource Updates",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Action: resourceCreate,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "create",
|
||||
Usage: "creates a new Mutable Resource",
|
||||
ArgsUsage: "<frequency>",
|
||||
Description: "creates a new Mutable Resource",
|
||||
Flags: []cli.Flag{SwarmResourceNameFlag, SwarmResourceDataOnCreateFlag, SwarmResourceMultihashFlag},
|
||||
},
|
||||
{
|
||||
Action: resourceUpdate,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "update",
|
||||
Usage: "updates the content of an existing Mutable Resource",
|
||||
ArgsUsage: "<Manifest Address or ENS domain> <0x Hex data>",
|
||||
Description: "updates the content of an existing Mutable Resource",
|
||||
Flags: []cli.Flag{SwarmResourceMultihashFlag},
|
||||
},
|
||||
{
|
||||
Action: resourceInfo,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
Name: "info",
|
||||
Usage: "obtains information about an existing Mutable Resource",
|
||||
ArgsUsage: "<Manifest Address or ENS domain>",
|
||||
Description: "obtains information about an existing Mutable Resource",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Action: list,
|
||||
CustomHelpTemplate: helpTemplate,
|
||||
|
|
@ -376,6 +433,11 @@ pv(1) tool to get a progress bar:
|
|||
// See config.go
|
||||
DumpConfigCommand,
|
||||
}
|
||||
|
||||
// append a hidden help subcommand to all commands that have subcommands
|
||||
// if a help command was already defined above, that one will take precedence.
|
||||
addDefaultHelpSubcommands(app.Commands)
|
||||
|
||||
sort.Sort(cli.CommandsByName(app.Commands))
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
|
|
@ -430,12 +492,14 @@ pv(1) tool to get a progress bar:
|
|||
app.Flags = append(app.Flags, rpcFlags...)
|
||||
app.Flags = append(app.Flags, debug.Flags...)
|
||||
app.Flags = append(app.Flags, swarmmetrics.Flags...)
|
||||
app.Flags = append(app.Flags, tracing.Flags...)
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
if err := debug.Setup(ctx); err != nil {
|
||||
if err := debug.Setup(ctx, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
swarmmetrics.Setup(ctx)
|
||||
tracing.Setup(ctx)
|
||||
return nil
|
||||
}
|
||||
app.After = func(ctx *cli.Context) error {
|
||||
|
|
@ -452,7 +516,8 @@ func main() {
|
|||
}
|
||||
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Println("Version:", SWARM_VERSION)
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", sv.VersionWithMeta)
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit:", gitCommit)
|
||||
}
|
||||
|
|
@ -546,6 +611,26 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr
|
|||
return decryptStoreAccount(ks, bzzaccount, utils.MakePasswordList(ctx))
|
||||
}
|
||||
|
||||
// getPrivKey returns the private key of the specified bzzaccount
|
||||
// Used only by client commands, such as `resource`
|
||||
func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
|
||||
// booting up the swarm node just as we do in bzzd action
|
||||
bzzconfig, err := buildConfig(ctx)
|
||||
if err != nil {
|
||||
utils.Fatalf("unable to configure swarm: %v", err)
|
||||
}
|
||||
cfg := defaultNodeConfig
|
||||
if _, err := os.Stat(bzzconfig.Path); err == nil {
|
||||
cfg.DataDir = bzzconfig.Path
|
||||
}
|
||||
utils.SetNodeConfig(ctx, &cfg)
|
||||
stack, err := node.New(&cfg)
|
||||
if err != nil {
|
||||
utils.Fatalf("can't create node: %v", err)
|
||||
}
|
||||
return getAccount(bzzconfig.BzzAccount, ctx, stack)
|
||||
}
|
||||
|
||||
func decryptStoreAccount(ks *keystore.KeyStore, account string, passwords []string) *ecdsa.PrivateKey {
|
||||
var a accounts.Account
|
||||
var err error
|
||||
|
|
@ -610,3 +695,16 @@ func injectBootnodes(srv *p2p.Server, nodes []string) {
|
|||
srv.AddPeer(n)
|
||||
}
|
||||
}
|
||||
|
||||
// addDefaultHelpSubcommand scans through defined CLI commands and adds
|
||||
// a basic help subcommand to each
|
||||
// if a help command is already defined, it will take precedence over the default.
|
||||
func addDefaultHelpSubcommands(commands []cli.Command) {
|
||||
for i := range commands {
|
||||
cmd := &commands[i]
|
||||
if cmd.Subcommands != nil {
|
||||
cmd.Subcommands = append(cmd.Subcommands, defaultSubcommandHelp)
|
||||
addDefaultHelpSubcommands(cmd.Subcommands)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
169
cmd/swarm/mru.go
Normal file
169
cmd/swarm/mru.go
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2016 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/>.
|
||||
|
||||
// Command resource allows the user to create and update signed mutable resource updates
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/mru"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
func NewGenericSigner(ctx *cli.Context) mru.Signer {
|
||||
return mru.NewGenericSigner(getPrivKey(ctx))
|
||||
}
|
||||
|
||||
// swarm resource create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
|
||||
// swarm resource update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
|
||||
// swarm resource info <Manifest Address or ENS domain>
|
||||
|
||||
func resourceCreate(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
|
||||
var (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
multihash = ctx.Bool(SwarmResourceMultihashFlag.Name)
|
||||
initialData = ctx.String(SwarmResourceDataOnCreateFlag.Name)
|
||||
name = ctx.String(SwarmResourceNameFlag.Name)
|
||||
)
|
||||
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Incorrect number of arguments")
|
||||
cli.ShowCommandHelpAndExit(ctx, "create", 1)
|
||||
return
|
||||
}
|
||||
signer := NewGenericSigner(ctx)
|
||||
frequency, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("Frequency formatting error: %s\n", err.Error())
|
||||
cli.ShowCommandHelpAndExit(ctx, "create", 1)
|
||||
return
|
||||
}
|
||||
|
||||
metadata := mru.ResourceMetadata{
|
||||
Name: name,
|
||||
Frequency: frequency,
|
||||
Owner: signer.Address(),
|
||||
}
|
||||
|
||||
var newResourceRequest *mru.Request
|
||||
if initialData != "" {
|
||||
initialDataBytes, err := hexutil.Decode(initialData)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing data: %s\n", err.Error())
|
||||
cli.ShowCommandHelpAndExit(ctx, "create", 1)
|
||||
return
|
||||
}
|
||||
newResourceRequest, err = mru.NewCreateUpdateRequest(&metadata)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error creating new resource request: %s", err)
|
||||
}
|
||||
newResourceRequest.SetData(initialDataBytes, multihash)
|
||||
if err = newResourceRequest.Sign(signer); err != nil {
|
||||
utils.Fatalf("Error signing resource update: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
newResourceRequest, err = mru.NewCreateRequest(&metadata)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error creating new resource request: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
manifestAddress, err := client.CreateResource(newResourceRequest)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error creating resource: %s", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
|
||||
|
||||
}
|
||||
|
||||
func resourceUpdate(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
|
||||
var (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
multihash = ctx.Bool(SwarmResourceMultihashFlag.Name)
|
||||
)
|
||||
|
||||
if len(args) < 2 {
|
||||
fmt.Println("Incorrect number of arguments")
|
||||
cli.ShowCommandHelpAndExit(ctx, "update", 1)
|
||||
return
|
||||
}
|
||||
signer := NewGenericSigner(ctx)
|
||||
manifestAddressOrDomain := args[0]
|
||||
data, err := hexutil.Decode(args[1])
|
||||
if err != nil {
|
||||
utils.Fatalf("Error parsing data: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve resource status and metadata out of the manifest
|
||||
updateRequest, err := client.GetResourceMetadata(manifestAddressOrDomain)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error retrieving resource status: %s", err.Error())
|
||||
}
|
||||
|
||||
// set the new data
|
||||
updateRequest.SetData(data, multihash)
|
||||
|
||||
// sign update
|
||||
if err = updateRequest.Sign(signer); err != nil {
|
||||
utils.Fatalf("Error signing resource update: %s", err.Error())
|
||||
}
|
||||
|
||||
// post update
|
||||
err = client.UpdateResource(updateRequest)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error updating resource: %s", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func resourceInfo(ctx *cli.Context) {
|
||||
var (
|
||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||
client = swarm.NewClient(bzzapi)
|
||||
)
|
||||
args := ctx.Args()
|
||||
if len(args) < 1 {
|
||||
fmt.Println("Incorrect number of arguments.")
|
||||
cli.ShowCommandHelpAndExit(ctx, "info", 1)
|
||||
return
|
||||
}
|
||||
manifestAddressOrDomain := args[0]
|
||||
metadata, err := client.GetResourceMetadata(manifestAddressOrDomain)
|
||||
if err != nil {
|
||||
utils.Fatalf("Error retrieving resource metadata: %s", err.Error())
|
||||
return
|
||||
}
|
||||
encodedMetadata, err := metadata.MarshalJSON()
|
||||
if err != nil {
|
||||
utils.Fatalf("Error encoding metadata to JSON for display:%s", err)
|
||||
}
|
||||
fmt.Println(string(encodedMetadata))
|
||||
}
|
||||
|
|
@ -37,8 +37,14 @@ import (
|
|||
)
|
||||
|
||||
func generateEndpoints(scheme string, cluster string, from int, to int) {
|
||||
if cluster == "prod" {
|
||||
cluster = ""
|
||||
} else {
|
||||
cluster = cluster + "."
|
||||
}
|
||||
|
||||
for port := from; port <= to; port++ {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s://%v.%s.swarm-gateways.net", scheme, port, cluster))
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s://%v.%sswarm-gateways.net", scheme, port, cluster))
|
||||
}
|
||||
|
||||
if includeLocalhost {
|
||||
|
|
@ -71,8 +77,9 @@ func cliUploadAndSync(c *cli.Context) error {
|
|||
log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash))
|
||||
|
||||
if filesize < 10 {
|
||||
time.Sleep(15 * time.Second)
|
||||
time.Sleep(35 * time.Second)
|
||||
} else {
|
||||
time.Sleep(15 * time.Second)
|
||||
time.Sleep(2 * time.Duration(filesize) * time.Second)
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +109,7 @@ func cliUploadAndSync(c *cli.Context) error {
|
|||
// fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file
|
||||
func fetch(hash string, endpoint string, original []byte, ruid string) error {
|
||||
log.Trace("sleeping", "ruid", ruid)
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
log.Trace("http get request", "ruid", ruid, "api", endpoint, "hash", hash)
|
||||
res, err := http.Get(endpoint + "/bzz:/" + hash + "/")
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func NewApp(gitCommit, usage string) *cli.App {
|
|||
app.Author = ""
|
||||
//app.Authors = nil
|
||||
app.Email = ""
|
||||
app.Version = params.Version
|
||||
app.Version = params.VersionWithMeta
|
||||
if len(gitCommit) >= 8 {
|
||||
app.Version += "-" + gitCommit[:8]
|
||||
}
|
||||
|
|
@ -205,7 +205,7 @@ var (
|
|||
}
|
||||
// Dashboard settings
|
||||
DashboardEnabledFlag = cli.BoolFlag{
|
||||
Name: "dashboard",
|
||||
Name: metrics.DashboardEnabledFlag,
|
||||
Usage: "Enable the dashboard",
|
||||
}
|
||||
DashboardAddrFlag = cli.StringFlag{
|
||||
|
|
@ -671,8 +671,7 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
|||
for _, url := range urls {
|
||||
node, err := discover.ParseNode(url)
|
||||
if err != nil {
|
||||
log.Error("Bootstrap URL invalid", "enode", url, "err", err)
|
||||
continue
|
||||
log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
|
||||
}
|
||||
cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
|
||||
}
|
||||
|
|
@ -1031,7 +1030,7 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) {
|
|||
}
|
||||
}
|
||||
|
||||
// checkExclusive verifies that only a single isntance of the provided flags was
|
||||
// checkExclusive verifies that only a single instance of the provided flags was
|
||||
// set by the user. Each flag might optionally be followed by a string type to
|
||||
// specialize it further.
|
||||
func checkExclusive(ctx *cli.Context, args ...interface{}) {
|
||||
|
|
@ -1240,7 +1239,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
|
|||
// RegisterDashboardService adds a dashboard to the stack.
|
||||
func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
|
||||
stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
return dashboard.New(cfg, commit)
|
||||
return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1254,7 +1253,7 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
|
|||
}
|
||||
|
||||
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
|
||||
// th egiven node.
|
||||
// the given node.
|
||||
func RegisterEthStatsService(stack *node.Node, url string) {
|
||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
// Retrieve both eth and les services
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -31,7 +32,9 @@ import (
|
|||
|
||||
// Lengths of hashes and addresses in bytes.
|
||||
const (
|
||||
// HashLength is the expected length of the hash
|
||||
HashLength = 32
|
||||
// AddressLength is the expected length of the adddress
|
||||
AddressLength = 20
|
||||
)
|
||||
|
||||
|
|
@ -120,6 +123,24 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
|||
return reflect.ValueOf(h)
|
||||
}
|
||||
|
||||
// Scan implements Scanner for database/sql.
|
||||
func (h *Hash) Scan(src interface{}) error {
|
||||
srcB, ok := src.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("can't scan %T into Hash", src)
|
||||
}
|
||||
if len(srcB) != HashLength {
|
||||
return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), HashLength)
|
||||
}
|
||||
copy(h[:], srcB)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements valuer for database/sql.
|
||||
func (h Hash) Value() (driver.Value, error) {
|
||||
return h[:], nil
|
||||
}
|
||||
|
||||
// UnprefixedHash allows marshaling a Hash without 0x prefix.
|
||||
type UnprefixedHash Hash
|
||||
|
||||
|
|
@ -229,6 +250,24 @@ func (a *Address) UnmarshalJSON(input []byte) error {
|
|||
return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
|
||||
}
|
||||
|
||||
// Scan implements Scanner for database/sql.
|
||||
func (a *Address) Scan(src interface{}) error {
|
||||
srcB, ok := src.([]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("can't scan %T into Address", src)
|
||||
}
|
||||
if len(srcB) != AddressLength {
|
||||
return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressLength)
|
||||
}
|
||||
copy(a[:], srcB)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements valuer for database/sql.
|
||||
func (a Address) Value() (driver.Value, error) {
|
||||
return a[:], nil
|
||||
}
|
||||
|
||||
// UnprefixedAddress allows marshaling an Address without 0x prefix.
|
||||
type UnprefixedAddress Address
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -193,3 +194,180 @@ func TestMixedcaseAccount_Address(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHash_Scan(t *testing.T) {
|
||||
type args struct {
|
||||
src interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "working scan",
|
||||
args: args{src: []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0x10, 0x00,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "non working scan",
|
||||
args: args{src: int64(1234567890)},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid length scan",
|
||||
args: args{src: []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := &Hash{}
|
||||
if err := h.Scan(tt.args.src); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Hash.Scan() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if !tt.wantErr {
|
||||
for i := range h {
|
||||
if h[i] != tt.args.src.([]byte)[i] {
|
||||
t.Errorf(
|
||||
"Hash.Scan() didn't scan the %d src correctly (have %X, want %X)",
|
||||
i, h[i], tt.args.src.([]byte)[i],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHash_Value(t *testing.T) {
|
||||
b := []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
0x10, 0x00,
|
||||
}
|
||||
var usedH Hash
|
||||
usedH.SetBytes(b)
|
||||
tests := []struct {
|
||||
name string
|
||||
h Hash
|
||||
want driver.Value
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Working value",
|
||||
h: usedH,
|
||||
want: b,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.h.Value()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Hash.Value() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Hash.Value() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddress_Scan(t *testing.T) {
|
||||
type args struct {
|
||||
src interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "working scan",
|
||||
args: args{src: []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "non working scan",
|
||||
args: args{src: int64(1234567890)},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid length scan",
|
||||
args: args{src: []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a,
|
||||
}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &Address{}
|
||||
if err := a.Scan(tt.args.src); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Address.Scan() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if !tt.wantErr {
|
||||
for i := range a {
|
||||
if a[i] != tt.args.src.([]byte)[i] {
|
||||
t.Errorf(
|
||||
"Address.Scan() didn't scan the %d src correctly (have %X, want %X)",
|
||||
i, a[i], tt.args.src.([]byte)[i],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddress_Value(t *testing.T) {
|
||||
b := []byte{
|
||||
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
|
||||
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
|
||||
}
|
||||
var usedA Address
|
||||
usedA.SetBytes(b)
|
||||
tests := []struct {
|
||||
name string
|
||||
a Address
|
||||
want driver.Value
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Working value",
|
||||
a: usedA,
|
||||
want: b,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.a.Value()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Address.Value() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Address.Value() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
|
|||
return snap.signers(), nil
|
||||
}
|
||||
|
||||
// GetSignersAtHash retrieves the state snapshot at a given block.
|
||||
// GetSignersAtHash retrieves the list of authorized signers at the specified block.
|
||||
func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
|
||||
header := api.chain.GetHeaderByHash(hash)
|
||||
if header == nil {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ const (
|
|||
// Clique proof-of-authority protocol constants.
|
||||
var (
|
||||
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||
blockPeriod = uint64(15) // Default minimum difference between two consecutive block's timestamps
|
||||
|
||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package clique
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -56,6 +57,13 @@ type Snapshot struct {
|
|||
Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating
|
||||
}
|
||||
|
||||
// signers implements the sort interface to allow sorting a list of addresses
|
||||
type signers []common.Address
|
||||
|
||||
func (s signers) Len() int { return len(s) }
|
||||
func (s signers) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 }
|
||||
func (s signers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||
// method does not initialize the set of recent signers, so only ever use if for
|
||||
// the genesis block.
|
||||
|
|
@ -286,18 +294,12 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
|||
|
||||
// signers retrieves the list of authorized signers in ascending order.
|
||||
func (s *Snapshot) signers() []common.Address {
|
||||
signers := make([]common.Address, 0, len(s.Signers))
|
||||
for signer := range s.Signers {
|
||||
signers = append(signers, signer)
|
||||
sigs := make([]common.Address, 0, len(s.Signers))
|
||||
for sig := range s.Signers {
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
for i := 0; i < len(signers); i++ {
|
||||
for j := i + 1; j < len(signers); j++ {
|
||||
if bytes.Compare(signers[i][:], signers[j][:]) > 0 {
|
||||
signers[i], signers[j] = signers[j], signers[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return signers
|
||||
sort.Sort(signers(sigs))
|
||||
return sigs
|
||||
}
|
||||
|
||||
// inturn returns if a signer at a given block height is in-turn or not.
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ func TestVoting(t *testing.T) {
|
|||
for j, vote := range tt.votes {
|
||||
headers[j] = &types.Header{
|
||||
Number: big.NewInt(int64(j) + 1),
|
||||
Time: big.NewInt(int64(j) * int64(blockPeriod)),
|
||||
Time: big.NewInt(int64(j) * 15),
|
||||
Coinbase: accounts.address(vote.voted),
|
||||
Extra: make([]byte, extraVanity+extraSeal),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,15 +214,6 @@ func swap(buffer []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
// prepare converts an ethash cache or dataset from a byte stream into the internal
|
||||
// int representation. All ethash methods work with ints to avoid constant byte to
|
||||
// int conversions as well as to handle both little and big endian systems.
|
||||
func prepare(dest []uint32, src []byte) {
|
||||
for i := 0; i < len(dest); i++ {
|
||||
dest[i] = binary.LittleEndian.Uint32(src[i*4:])
|
||||
}
|
||||
}
|
||||
|
||||
// fnv is an algorithm inspired by the FNV hash, which in some cases is used as
|
||||
// a non-associative substitute for XOR. Note that we multiply the prime with
|
||||
// the full 32-bit input, in contrast with the FNV-1 spec which multiplies the
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package ethash
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
|
|
@ -30,6 +31,15 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// prepare converts an ethash cache or dataset from a byte stream into the internal
|
||||
// int representation. All ethash methods work with ints to avoid constant byte to
|
||||
// int conversions as well as to handle both little and big endian systems.
|
||||
func prepare(dest []uint32, src []byte) {
|
||||
for i := 0; i < len(dest); i++ {
|
||||
dest[i] = binary.LittleEndian.Uint32(src[i*4:])
|
||||
}
|
||||
}
|
||||
|
||||
// Tests whether the dataset size calculator works correctly by cross checking the
|
||||
// hard coded lookup table with the value generated by it.
|
||||
func TestSizeCalculations(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -31,7 +32,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
set "gopkg.in/fatih/set.v0"
|
||||
)
|
||||
|
||||
// Ethash proof-of-work protocol constants.
|
||||
|
|
@ -181,7 +181,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo
|
|||
return errTooManyUncles
|
||||
}
|
||||
// Gather the set of past uncles and ancestors
|
||||
uncles, ancestors := set.New(), make(map[common.Hash]*types.Header)
|
||||
uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header)
|
||||
|
||||
number, parent := block.NumberU64()-1, block.ParentHash()
|
||||
for i := 0; i < 7; i++ {
|
||||
|
|
@ -202,7 +202,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo
|
|||
for _, uncle := range block.Uncles() {
|
||||
// Make sure every uncle is rewarded only once
|
||||
hash := uncle.Hash()
|
||||
if uncles.Has(hash) {
|
||||
if uncles.Contains(hash) {
|
||||
return errDuplicateUncle
|
||||
}
|
||||
uncles.Add(hash)
|
||||
|
|
@ -365,7 +365,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
|||
}
|
||||
// calculate a fake block number for the ice-age delay:
|
||||
// https://github.com/ethereum/EIPs/pull/669
|
||||
// fake_block_number = min(0, block.number - 3_000_000
|
||||
// fake_block_number = max(0, block.number - 3_000_000)
|
||||
fakeBlockNumber := new(big.Int)
|
||||
if parent.Number.Cmp(big2999999) >= 0 {
|
||||
fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) // Note, parent is 1 less than the actual block number
|
||||
|
|
|
|||
|
|
@ -450,15 +450,19 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
|
|||
}
|
||||
log.Info("Exporting batch of blocks", "count", last-first+1)
|
||||
|
||||
start, reported := time.Now(), time.Now()
|
||||
for nr := first; nr <= last; nr++ {
|
||||
block := bc.GetBlockByNumber(nr)
|
||||
if block == nil {
|
||||
return fmt.Errorf("export failed on #%d: not found", nr)
|
||||
}
|
||||
|
||||
if err := block.EncodeRLP(w); err != nil {
|
||||
return err
|
||||
}
|
||||
if time.Since(reported) >= statsReportLimit {
|
||||
log.Info("Exporting blocks", "exported", block.NumberU64()-first, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
reported = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -1012,7 +1016,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
|
|||
// Do a sanity check that the provided chain is actually ordered and linked
|
||||
for i := 1; i < len(chain); i++ {
|
||||
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
|
||||
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||
// Chain broke ancestry, log a message (programming error) and skip insertion
|
||||
log.Error("Non contiguous block insert", "number", chain[i].Number(), "hash", chain[i].Hash(),
|
||||
"parent", chain[i].ParentHash(), "prevnumber", chain[i-1].Number(), "prevhash", chain[i-1].Hash())
|
||||
|
||||
|
|
@ -1203,8 +1207,8 @@ type insertStats struct {
|
|||
startTime mclock.AbsTime
|
||||
}
|
||||
|
||||
// statsReportLimit is the time limit during import after which we always print
|
||||
// out progress. This avoids the user wondering what's going on.
|
||||
// statsReportLimit is the time limit during import and export after which we
|
||||
// always print out progress. This avoids the user wondering what's going on.
|
||||
const statsReportLimit = 8 * time.Second
|
||||
|
||||
// report prints statistics if some number of blocks have been processed
|
||||
|
|
|
|||
|
|
@ -1146,8 +1146,7 @@ func TestEIP155Transition(t *testing.T) {
|
|||
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key)
|
||||
}
|
||||
)
|
||||
switch i {
|
||||
case 0:
|
||||
if i == 0 {
|
||||
tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -22,16 +22,22 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// errSectionOutOfBounds is returned if the user tried to add more bloom filters
|
||||
// to the batch than available space, or if tries to retrieve above the capacity,
|
||||
var errSectionOutOfBounds = errors.New("section out of bounds")
|
||||
var (
|
||||
// errSectionOutOfBounds is returned if the user tried to add more bloom filters
|
||||
// to the batch than available space, or if tries to retrieve above the capacity.
|
||||
errSectionOutOfBounds = errors.New("section out of bounds")
|
||||
|
||||
// errBloomBitOutOfBounds is returned if the user tried to retrieve specified
|
||||
// bit bloom above the capacity.
|
||||
errBloomBitOutOfBounds = errors.New("bloom bit out of bounds")
|
||||
)
|
||||
|
||||
// Generator takes a number of bloom filters and generates the rotated bloom bits
|
||||
// to be used for batched filtering.
|
||||
type Generator struct {
|
||||
blooms [types.BloomBitLength][]byte // Rotated blooms for per-bit matching
|
||||
sections uint // Number of sections to batch together
|
||||
nextBit uint // Next bit to set when adding a bloom
|
||||
nextSec uint // Next section to set when adding a bloom
|
||||
}
|
||||
|
||||
// NewGenerator creates a rotated bloom generator that can iteratively fill a
|
||||
|
|
@ -51,15 +57,15 @@ func NewGenerator(sections uint) (*Generator, error) {
|
|||
// in memory accordingly.
|
||||
func (b *Generator) AddBloom(index uint, bloom types.Bloom) error {
|
||||
// Make sure we're not adding more bloom filters than our capacity
|
||||
if b.nextBit >= b.sections {
|
||||
if b.nextSec >= b.sections {
|
||||
return errSectionOutOfBounds
|
||||
}
|
||||
if b.nextBit != index {
|
||||
if b.nextSec != index {
|
||||
return errors.New("bloom filter with unexpected index")
|
||||
}
|
||||
// Rotate the bloom and insert into our collection
|
||||
byteIndex := b.nextBit / 8
|
||||
bitMask := byte(1) << byte(7-b.nextBit%8)
|
||||
byteIndex := b.nextSec / 8
|
||||
bitMask := byte(1) << byte(7-b.nextSec%8)
|
||||
|
||||
for i := 0; i < types.BloomBitLength; i++ {
|
||||
bloomByteIndex := types.BloomByteLength - 1 - i/8
|
||||
|
|
@ -69,7 +75,7 @@ func (b *Generator) AddBloom(index uint, bloom types.Bloom) error {
|
|||
b.blooms[i][byteIndex] |= bitMask
|
||||
}
|
||||
}
|
||||
b.nextBit++
|
||||
b.nextSec++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -77,11 +83,11 @@ func (b *Generator) AddBloom(index uint, bloom types.Bloom) error {
|
|||
// Bitset returns the bit vector belonging to the given bit index after all
|
||||
// blooms have been added.
|
||||
func (b *Generator) Bitset(idx uint) ([]byte, error) {
|
||||
if b.nextBit != b.sections {
|
||||
if b.nextSec != b.sections {
|
||||
return nil, errors.New("bloom not fully generated yet")
|
||||
}
|
||||
if idx >= b.sections {
|
||||
return nil, errSectionOutOfBounds
|
||||
if idx >= types.BloomBitLength {
|
||||
return nil, errBloomBitOutOfBounds
|
||||
}
|
||||
return b.blooms[idx], nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ type partialMatches struct {
|
|||
// It can also have the actual results set to be used as a delivery data struct.
|
||||
//
|
||||
// The contest and error fields are used by the light client to terminate matching
|
||||
// early if an error is enountered on some path of the pipeline.
|
||||
// early if an error is encountered on some path of the pipeline.
|
||||
type Retrieval struct {
|
||||
Bit uint
|
||||
Sections []uint64
|
||||
|
|
@ -218,7 +218,7 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin
|
|||
// run creates a daisy-chain of sub-matchers, one for the address set and one
|
||||
// for each topic set, each sub-matcher receiving a section only if the previous
|
||||
// ones have all found a potential match in one of the blocks of the section,
|
||||
// then binary AND-ing its own matches and forwaring the result to the next one.
|
||||
// then binary AND-ing its own matches and forwarding the result to the next one.
|
||||
//
|
||||
// The method starts feeding the section indexes into the first sub-matcher on a
|
||||
// new goroutine and returns a sink channel receiving the results.
|
||||
|
|
@ -543,7 +543,7 @@ func (s *MatcherSession) Error() error {
|
|||
}
|
||||
|
||||
// AllocateRetrieval assigns a bloom bit index to a client process that can either
|
||||
// immediately reuest and fetch the section contents assigned to this bit or wait
|
||||
// immediately request and fetch the section contents assigned to this bit or wait
|
||||
// a little while for more sections to be requested.
|
||||
func (s *MatcherSession) AllocateRetrieval() (uint, bool) {
|
||||
fetcher := make(chan uint)
|
||||
|
|
@ -599,8 +599,8 @@ func (s *MatcherSession) DeliverSections(bit uint, sections []uint64, bitsets []
|
|||
}
|
||||
}
|
||||
|
||||
// Multiplex polls the matcher session for rerieval tasks and multiplexes it into
|
||||
// the reuested retrieval queue to be serviced together with other sessions.
|
||||
// Multiplex polls the matcher session for retrieval tasks and multiplexes it into
|
||||
// the requested retrieval queue to be serviced together with other sessions.
|
||||
//
|
||||
// This method will block for the lifetime of the session. Even after termination
|
||||
// of the session, any request in-flight need to be responded to! Empty responses
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in
|
|||
// Track the number of retrieval requests made
|
||||
var requested uint32
|
||||
|
||||
// Start the matching session for the filter and the retriver goroutines
|
||||
// Start the matching session for the filter and the retriever goroutines
|
||||
quit := make(chan struct{})
|
||||
matches := make(chan uint64, 16)
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash
|
|||
}
|
||||
}
|
||||
|
||||
// CanTransfer checks wether there are enough funds in the address' account to make a transfer.
|
||||
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
|
||||
// This does not take the necessary gas in to account to make the transfer valid.
|
||||
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
|
||||
return db.GetBalance(addr).Cmp(amount) >= 0
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int)
|
|||
// Do a sanity check that the provided chain is actually ordered and linked
|
||||
for i := 1; i < len(chain); i++ {
|
||||
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
|
||||
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||
// Chain broke ancestry, log a message (programming error) and skip insertion
|
||||
log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(),
|
||||
"parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash())
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ var (
|
|||
The State Transitioning Model
|
||||
|
||||
A state transition is a change made when a transaction is applied to the current world state
|
||||
The state transitioning model does all all the necessary work to work out a valid new state root.
|
||||
The state transitioning model does all the necessary work to work out a valid new state root.
|
||||
|
||||
1) Nonce handling
|
||||
2) Pre pay gas
|
||||
|
|
@ -178,8 +178,8 @@ func (st *StateTransition) preCheck() error {
|
|||
}
|
||||
|
||||
// TransitionDb will transition the state by applying the current message and
|
||||
// returning the result including the the used gas. It returns an error if it
|
||||
// failed. An error indicates a consensus issue.
|
||||
// returning the result including the used gas. It returns an error if failed.
|
||||
// An error indicates a consensus issue.
|
||||
func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) {
|
||||
if err = st.preCheck(); err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ func (l *txPricedList) Removed() {
|
|||
}
|
||||
|
||||
// Cap finds all the transactions below the given price threshold, drops them
|
||||
// from the priced list and returs them for further removal from the entire pool.
|
||||
// from the priced list and returns them for further removal from the entire pool.
|
||||
func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions {
|
||||
drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop
|
||||
save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ type TxPoolConfig struct {
|
|||
PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
|
||||
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)
|
||||
|
||||
AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account
|
||||
AccountSlots uint64 // Number of executable transaction slots guaranteed per account
|
||||
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
|
||||
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
|
||||
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
|
||||
|
|
@ -1041,7 +1041,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) {
|
|||
}
|
||||
if queued > pool.config.GlobalQueue {
|
||||
// Sort all accounts with queued transactions by heartbeat
|
||||
addresses := make(addresssByHeartbeat, 0, len(pool.queue))
|
||||
addresses := make(addressesByHeartbeat, 0, len(pool.queue))
|
||||
for addr := range pool.queue {
|
||||
if !pool.locals.contains(addr) { // don't drop locals
|
||||
addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]})
|
||||
|
|
@ -1127,11 +1127,11 @@ type addressByHeartbeat struct {
|
|||
heartbeat time.Time
|
||||
}
|
||||
|
||||
type addresssByHeartbeat []addressByHeartbeat
|
||||
type addressesByHeartbeat []addressByHeartbeat
|
||||
|
||||
func (a addresssByHeartbeat) Len() int { return len(a) }
|
||||
func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) }
|
||||
func (a addresssByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a addressesByHeartbeat) Len() int { return len(a) }
|
||||
func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) }
|
||||
func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
// accountSet is simply a set of addresses to check for existence, and a signer
|
||||
// capable of deriving addresses from transactions.
|
||||
|
|
|
|||
|
|
@ -266,9 +266,9 @@ func (s Transactions) GetRlp(i int) []byte {
|
|||
return enc
|
||||
}
|
||||
|
||||
// TxDifference returns a new set t which is the difference between a to b.
|
||||
func TxDifference(a, b Transactions) (keep Transactions) {
|
||||
keep = make(Transactions, 0, len(a))
|
||||
// TxDifference returns a new set which is the difference between a and b.
|
||||
func TxDifference(a, b Transactions) Transactions {
|
||||
keep := make(Transactions, 0, len(a))
|
||||
|
||||
remove := make(map[common.Hash]struct{})
|
||||
for _, tx := range b {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ func (c *sha256hash) Run(input []byte) ([]byte, error) {
|
|||
return h[:], nil
|
||||
}
|
||||
|
||||
// RIPMED160 implemented as a native contract.
|
||||
// RIPEMD160 implemented as a native contract.
|
||||
type ripemd160hash struct{}
|
||||
|
||||
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||
|
|
|
|||
|
|
@ -26,4 +26,5 @@ var (
|
|||
ErrTraceLimitReached = errors.New("the number of logs reached the specified limit")
|
||||
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
|
||||
ErrContractAddressCollision = errors.New("contract address collision")
|
||||
ErrNoCompatibleInterpreter = errors.New("no compatible interpreter")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,20 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
|
|||
return RunPrecompiledContract(p, input, contract)
|
||||
}
|
||||
}
|
||||
return evm.interpreter.Run(contract, input)
|
||||
for _, interpreter := range evm.interpreters {
|
||||
if interpreter.CanRun(contract.Code) {
|
||||
if evm.interpreter != interpreter {
|
||||
// Ensure that the interpreter pointer is set back
|
||||
// to its current value upon return.
|
||||
defer func(i Interpreter) {
|
||||
evm.interpreter = i
|
||||
}(evm.interpreter)
|
||||
evm.interpreter = interpreter
|
||||
}
|
||||
return interpreter.Run(contract, input)
|
||||
}
|
||||
}
|
||||
return nil, ErrNoCompatibleInterpreter
|
||||
}
|
||||
|
||||
// Context provides the EVM with auxiliary information. Once provided
|
||||
|
|
@ -103,7 +116,8 @@ type EVM struct {
|
|||
vmConfig Config
|
||||
// global (to this context) ethereum virtual machine
|
||||
// used throughout the execution of the tx.
|
||||
interpreter *Interpreter
|
||||
interpreters []Interpreter
|
||||
interpreter Interpreter
|
||||
// abort is used to abort the EVM calling operations
|
||||
// NOTE: must be set atomically
|
||||
abort int32
|
||||
|
|
@ -122,9 +136,12 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
|
|||
vmConfig: vmConfig,
|
||||
chainConfig: chainConfig,
|
||||
chainRules: chainConfig.Rules(ctx.BlockNumber),
|
||||
interpreters: make([]Interpreter, 1),
|
||||
}
|
||||
|
||||
evm.interpreter = NewInterpreter(evm, vmConfig)
|
||||
evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig)
|
||||
evm.interpreter = evm.interpreters[0]
|
||||
|
||||
return evm
|
||||
}
|
||||
|
||||
|
|
@ -134,6 +151,11 @@ func (evm *EVM) Cancel() {
|
|||
atomic.StoreInt32(&evm.abort, 1)
|
||||
}
|
||||
|
||||
// Interpreter returns the current interpreter
|
||||
func (evm *EVM) Interpreter() Interpreter {
|
||||
return evm.interpreter
|
||||
}
|
||||
|
||||
// Call executes the contract associated with the addr with the given input as
|
||||
// parameters. It also handles any necessary value transfer required and takes
|
||||
// the necessary steps to create accounts and reverses the state in case of an
|
||||
|
|
@ -291,9 +313,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// Make sure the readonly is only set if we aren't in readonly yet
|
||||
// this makes also sure that the readonly flag isn't removed for
|
||||
// child calls.
|
||||
if !evm.interpreter.readOnly {
|
||||
evm.interpreter.readOnly = true
|
||||
defer func() { evm.interpreter.readOnly = false }()
|
||||
if !evm.interpreter.IsReadOnly() {
|
||||
evm.interpreter.SetReadOnly(true)
|
||||
defer func() { evm.interpreter.SetReadOnly(false) }()
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -319,9 +341,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
return ret, contract.Gas, err
|
||||
}
|
||||
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
|
|
@ -330,39 +351,38 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
||||
}
|
||||
// Ensure there's no existing contract already at the designated address
|
||||
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||
|
||||
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
||||
contractHash := evm.StateDB.GetCodeHash(contractAddr)
|
||||
if evm.StateDB.GetNonce(contractAddr) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
|
||||
// Ensure there's no existing contract already at the designated address
|
||||
contractHash := evm.StateDB.GetCodeHash(address)
|
||||
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
|
||||
return nil, common.Address{}, 0, ErrContractAddressCollision
|
||||
}
|
||||
// Create a new account on the state
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
evm.StateDB.CreateAccount(contractAddr)
|
||||
evm.StateDB.CreateAccount(address)
|
||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||
evm.StateDB.SetNonce(contractAddr, 1)
|
||||
evm.StateDB.SetNonce(address, 1)
|
||||
}
|
||||
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
|
||||
evm.Transfer(evm.StateDB, caller.Address(), address, value)
|
||||
|
||||
// initialise a new contract and set the code that is to be used by the
|
||||
// EVM. The contract is a scoped environment for this execution context
|
||||
// only.
|
||||
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
|
||||
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||
contract := NewContract(caller, AccountRef(address), value, gas)
|
||||
contract.SetCallCode(&address, crypto.Keccak256Hash(code), code)
|
||||
|
||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||
return nil, contractAddr, gas, nil
|
||||
return nil, address, gas, nil
|
||||
}
|
||||
|
||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value)
|
||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value)
|
||||
}
|
||||
start := time.Now()
|
||||
|
||||
ret, err = run(evm, contract, nil)
|
||||
ret, err := run(evm, contract, nil)
|
||||
|
||||
// check whether the max code size has been exceeded
|
||||
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
|
||||
|
|
@ -373,7 +393,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
if err == nil && !maxCodeSizeExceeded {
|
||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||
if contract.UseGas(createDataGas) {
|
||||
evm.StateDB.SetCode(contractAddr, ret)
|
||||
evm.StateDB.SetCode(address, ret)
|
||||
} else {
|
||||
err = ErrCodeStoreOutOfGas
|
||||
}
|
||||
|
|
@ -395,11 +415,24 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
||||
}
|
||||
return ret, contractAddr, contract.Gas, err
|
||||
return ret, address, contract.Gas, err
|
||||
|
||||
}
|
||||
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
|
||||
return evm.create(caller, code, gas, value, contractAddr)
|
||||
}
|
||||
|
||||
// Create2 creates a new contract using code as deployment code.
|
||||
//
|
||||
// The different between Create2 with Create is Create2 uses sha3(msg.sender ++ salt ++ init_code)[12:]
|
||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), code)
|
||||
return evm.create(caller, code, gas, endowment, contractAddr)
|
||||
}
|
||||
|
||||
// ChainConfig returns the environment's chain configuration
|
||||
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||
|
||||
// Interpreter returns the EVM interpreter
|
||||
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||
|
|
|
|||
|
|
@ -241,6 +241,10 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta
|
|||
return gas, nil
|
||||
}
|
||||
|
||||
func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gt.ExtcodeHash, nil
|
||||
}
|
||||
|
||||
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
|
|
@ -289,6 +293,18 @@ func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
|
|||
return gas, nil
|
||||
}
|
||||
|
||||
func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var overflow bool
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow {
|
||||
return 0, errGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
|
||||
func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
return gt.Balance, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,45 +37,45 @@ var (
|
|||
errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
|
||||
)
|
||||
|
||||
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
math.U256(y.Add(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
math.U256(y.Sub(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(math.U256(x.Mul(x, y)))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
interpreter.intPool.put(y)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
if y.Sign() != 0 {
|
||||
math.U256(y.Div(x, y))
|
||||
} else {
|
||||
y.SetUint64(0)
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||
res := evm.interpreter.intPool.getZero()
|
||||
res := interpreter.intPool.getZero()
|
||||
|
||||
if y.Sign() == 0 || x.Sign() == 0 {
|
||||
stack.push(res)
|
||||
|
|
@ -88,24 +88,24 @@ func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||
}
|
||||
stack.push(math.U256(res))
|
||||
}
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
if y.Sign() == 0 {
|
||||
stack.push(x.SetUint64(0))
|
||||
} else {
|
||||
stack.push(math.U256(x.Mod(x, y)))
|
||||
}
|
||||
evm.interpreter.intPool.put(y)
|
||||
interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
||||
res := evm.interpreter.intPool.getZero()
|
||||
res := interpreter.intPool.getZero()
|
||||
|
||||
if y.Sign() == 0 {
|
||||
stack.push(res)
|
||||
|
|
@ -118,20 +118,20 @@ func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||
}
|
||||
stack.push(math.U256(res))
|
||||
}
|
||||
evm.interpreter.intPool.put(x, y)
|
||||
interpreter.intPool.put(x, y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
base, exponent := stack.pop(), stack.pop()
|
||||
stack.push(math.Exp(base, exponent))
|
||||
|
||||
evm.interpreter.intPool.put(base, exponent)
|
||||
interpreter.intPool.put(base, exponent)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
back := stack.pop()
|
||||
if back.Cmp(big.NewInt(31)) < 0 {
|
||||
bit := uint(back.Uint64()*8 + 7)
|
||||
|
|
@ -147,39 +147,39 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
|
|||
stack.push(math.U256(num))
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(back)
|
||||
interpreter.intPool.put(back)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x := stack.peek()
|
||||
math.U256(x.Not(x))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
if x.Cmp(y) < 0 {
|
||||
y.SetUint64(1)
|
||||
} else {
|
||||
y.SetUint64(0)
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
if x.Cmp(y) > 0 {
|
||||
y.SetUint64(1)
|
||||
} else {
|
||||
y.SetUint64(0)
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
|
||||
xSign := x.Cmp(tt255)
|
||||
|
|
@ -199,11 +199,11 @@ func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
|||
y.SetUint64(0)
|
||||
}
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
|
||||
xSign := x.Cmp(tt255)
|
||||
|
|
@ -223,22 +223,22 @@ func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
|||
y.SetUint64(0)
|
||||
}
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
if x.Cmp(y) == 0 {
|
||||
y.SetUint64(1)
|
||||
} else {
|
||||
y.SetUint64(0)
|
||||
}
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x := stack.peek()
|
||||
if x.Sign() > 0 {
|
||||
x.SetUint64(0)
|
||||
|
|
@ -248,31 +248,31 @@ func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.pop()
|
||||
stack.push(x.And(x, y))
|
||||
|
||||
evm.interpreter.intPool.put(y)
|
||||
interpreter.intPool.put(y)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
y.Or(x, y)
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y := stack.pop(), stack.peek()
|
||||
y.Xor(x, y)
|
||||
|
||||
evm.interpreter.intPool.put(x)
|
||||
interpreter.intPool.put(x)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
th, val := stack.pop(), stack.peek()
|
||||
if th.Cmp(common.Big32) < 0 {
|
||||
b := math.Byte(val, 32, int(th.Int64()))
|
||||
|
|
@ -280,11 +280,11 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||
} else {
|
||||
val.SetUint64(0)
|
||||
}
|
||||
evm.interpreter.intPool.put(th)
|
||||
interpreter.intPool.put(th)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
x.Add(x, y)
|
||||
|
|
@ -293,11 +293,11 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
|||
} else {
|
||||
stack.push(x.SetUint64(0))
|
||||
}
|
||||
evm.interpreter.intPool.put(y, z)
|
||||
interpreter.intPool.put(y, z)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||
if z.Cmp(bigZero) > 0 {
|
||||
x.Mul(x, y)
|
||||
|
|
@ -306,17 +306,17 @@ func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
|||
} else {
|
||||
stack.push(x.SetUint64(0))
|
||||
}
|
||||
evm.interpreter.intPool.put(y, z)
|
||||
interpreter.intPool.put(y, z)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// opSHL implements Shift Left
|
||||
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
|
||||
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
|
||||
func opSHL(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
||||
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
|
||||
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
|
||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
||||
|
||||
if shift.Cmp(common.Big256) >= 0 {
|
||||
value.SetUint64(0)
|
||||
|
|
@ -331,10 +331,10 @@ func opSHL(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
|||
// opSHR implements Logical Shift Right
|
||||
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
|
||||
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
|
||||
func opSHR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
||||
shift, value := math.U256(stack.pop()), math.U256(stack.peek())
|
||||
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
|
||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
||||
|
||||
if shift.Cmp(common.Big256) >= 0 {
|
||||
value.SetUint64(0)
|
||||
|
|
@ -349,10 +349,10 @@ func opSHR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
|||
// opSAR implements Arithmetic Shift Right
|
||||
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
|
||||
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
|
||||
func opSAR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one
|
||||
shift, value := math.U256(stack.pop()), math.S256(stack.pop())
|
||||
defer evm.interpreter.intPool.put(shift) // First operand back into the pool
|
||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
||||
|
||||
if shift.Cmp(common.Big256) >= 0 {
|
||||
if value.Sign() > 0 {
|
||||
|
|
@ -370,57 +370,58 @@ func opSAR(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
data := memory.Get(offset.Int64(), size.Int64())
|
||||
hash := crypto.Keccak256(data)
|
||||
evm := interpreter.evm
|
||||
|
||||
if evm.vmConfig.EnablePreimageRecording {
|
||||
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
|
||||
}
|
||||
stack.push(evm.interpreter.intPool.get().SetBytes(hash))
|
||||
stack.push(interpreter.intPool.get().SetBytes(hash))
|
||||
|
||||
evm.interpreter.intPool.put(offset, size)
|
||||
interpreter.intPool.put(offset, size)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(contract.Address().Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
slot := stack.peek()
|
||||
slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot)))
|
||||
slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.Origin.Big())
|
||||
func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.evm.Origin.Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(contract.Caller().Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().Set(contract.value))
|
||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().Set(contract.value))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
||||
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
|
||||
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
memOffset = stack.pop()
|
||||
dataOffset = stack.pop()
|
||||
|
|
@ -428,48 +429,48 @@ func opCallDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
|
|||
)
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length))
|
||||
|
||||
evm.interpreter.intPool.put(memOffset, dataOffset, length)
|
||||
interpreter.intPool.put(memOffset, dataOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData))))
|
||||
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData))))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
memOffset = stack.pop()
|
||||
dataOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
|
||||
end = evm.interpreter.intPool.get().Add(dataOffset, length)
|
||||
end = interpreter.intPool.get().Add(dataOffset, length)
|
||||
)
|
||||
defer evm.interpreter.intPool.put(memOffset, dataOffset, length, end)
|
||||
defer interpreter.intPool.put(memOffset, dataOffset, length, end)
|
||||
|
||||
if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
|
||||
if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() {
|
||||
return nil, errReturnDataOutOfBounds
|
||||
}
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), evm.interpreter.returnData[dataOffset.Uint64():end.Uint64()])
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
slot := stack.peek()
|
||||
slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
|
||||
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
||||
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
l := interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
||||
stack.push(l)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
memOffset = stack.pop()
|
||||
codeOffset = stack.pop()
|
||||
|
|
@ -478,114 +479,146 @@ func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
|||
codeCopy := getDataBig(contract.Code, codeOffset, length)
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
addr = common.BigToAddress(stack.pop())
|
||||
memOffset = stack.pop()
|
||||
codeOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length)
|
||||
codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length)
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
evm.interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
interpreter.intPool.put(memOffset, codeOffset, length)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice))
|
||||
// opExtCodeHash returns the code hash of a specified account.
|
||||
// There are several cases when the function is called, while we can relay everything
|
||||
// to `state.GetCodeHash` function to ensure the correctness.
|
||||
// (1) Caller tries to get the code hash of a normal contract account, state
|
||||
// should return the relative code hash and set it as the result.
|
||||
//
|
||||
// (2) Caller tries to get the code hash of a non-existent account, state should
|
||||
// return common.Hash{} and zero will be set as the result.
|
||||
//
|
||||
// (3) Caller tries to get the code hash for an account without contract code,
|
||||
// state should return emptyCodeHash(0xc5d246...) as the result.
|
||||
//
|
||||
// (4) Caller tries to get the code hash of a precompiled account, the result
|
||||
// should be zero or emptyCodeHash.
|
||||
//
|
||||
// It is worth noting that in order to avoid unnecessary create and clean,
|
||||
// all precompile accounts on mainnet have been transferred 1 wei, so the return
|
||||
// here should be emptyCodeHash.
|
||||
// If the precompile account is not transferred any amount on a private or
|
||||
// customized chain, the return value will be zero.
|
||||
//
|
||||
// (5) Caller tries to get the code hash for an account which is marked as suicided
|
||||
// in the current transaction, the code hash of this account should be returned.
|
||||
//
|
||||
// (6) Caller tries to get the code hash for an account which is marked as deleted,
|
||||
// this account should be regarded as a non-existent account and zero should be returned.
|
||||
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
slot := stack.peek()
|
||||
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(common.BigToAddress(slot)).Bytes())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
num := stack.pop()
|
||||
|
||||
n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257)
|
||||
if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
|
||||
stack.push(evm.GetHash(num.Uint64()).Big())
|
||||
n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257)
|
||||
if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 {
|
||||
stack.push(interpreter.evm.GetHash(num.Uint64()).Big())
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
}
|
||||
evm.interpreter.intPool.put(num, n)
|
||||
interpreter.intPool.put(num, n)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.Coinbase.Big())
|
||||
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.evm.Coinbase.Big())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Time)))
|
||||
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.BlockNumber)))
|
||||
func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Difficulty)))
|
||||
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(evm.interpreter.intPool.get().SetUint64(evm.GasLimit)))
|
||||
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
interpreter.intPool.put(stack.pop())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset := stack.pop()
|
||||
val := evm.interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
|
||||
val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
|
||||
stack.push(val)
|
||||
|
||||
evm.interpreter.intPool.put(offset)
|
||||
interpreter.intPool.put(offset)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// pop value of the stack
|
||||
mStart, val := stack.pop(), stack.pop()
|
||||
memory.Set32(mStart.Uint64(), val)
|
||||
|
||||
evm.interpreter.intPool.put(mStart, val)
|
||||
interpreter.intPool.put(mStart, val)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
off, val := stack.pop().Int64(), stack.pop().Int64()
|
||||
memory.store[off] = byte(val & 0xff)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := stack.peek()
|
||||
val := evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||
val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
||||
loc.SetBytes(val.Bytes())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
loc := common.BigToHash(stack.pop())
|
||||
val := stack.pop()
|
||||
evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
||||
interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
||||
|
||||
evm.interpreter.intPool.put(val)
|
||||
interpreter.intPool.put(val)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos := stack.pop()
|
||||
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||
nop := contract.GetOp(pos.Uint64())
|
||||
|
|
@ -593,11 +626,11 @@ func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||
}
|
||||
*pc = pos.Uint64()
|
||||
|
||||
evm.interpreter.intPool.put(pos)
|
||||
interpreter.intPool.put(pos)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos, cond := stack.pop(), stack.pop()
|
||||
if cond.Sign() != 0 {
|
||||
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||
|
|
@ -609,55 +642,55 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St
|
|||
*pc++
|
||||
}
|
||||
|
||||
evm.interpreter.intPool.put(pos, cond)
|
||||
interpreter.intPool.put(pos, cond)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(*pc))
|
||||
func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetUint64(*pc))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len())))
|
||||
func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len())))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas))
|
||||
func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.intPool.get().SetUint64(contract.Gas))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
value = stack.pop()
|
||||
offset, size = stack.pop(), stack.pop()
|
||||
input = memory.Get(offset.Int64(), size.Int64())
|
||||
gas = contract.Gas
|
||||
)
|
||||
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
||||
if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockNumber) {
|
||||
gas -= gas / 64
|
||||
}
|
||||
|
||||
contract.UseGas(gas)
|
||||
res, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value)
|
||||
// Push item on the stack based on the returned error. If the ruleset is
|
||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||
// rule) and treat as an error, if the ruleset is frontier we must
|
||||
// ignore this error and pretend the operation was successful.
|
||||
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(addr.Big())
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
evm.interpreter.intPool.put(value, offset, size)
|
||||
interpreter.intPool.put(value, offset, size)
|
||||
|
||||
if suberr == errExecutionReverted {
|
||||
return res, nil
|
||||
|
|
@ -665,10 +698,38 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas in in evm.callGasTemp.
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
gas := evm.callGasTemp
|
||||
func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
endowment = stack.pop()
|
||||
offset, size = stack.pop(), stack.pop()
|
||||
salt = stack.pop()
|
||||
input = memory.Get(offset.Int64(), size.Int64())
|
||||
gas = contract.Gas
|
||||
)
|
||||
|
||||
// Apply EIP150
|
||||
gas -= gas / 64
|
||||
contract.UseGas(gas)
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt)
|
||||
// Push item on the stack based on the returned error.
|
||||
if suberr != nil {
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(addr.Big())
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
interpreter.intPool.put(endowment, offset, size, salt)
|
||||
|
||||
if suberr == errExecutionReverted {
|
||||
return res, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas in in interpreter.evm.callGasTemp.
|
||||
interpreter.intPool.put(stack.pop())
|
||||
gas := interpreter.evm.callGasTemp
|
||||
// Pop other call parameters.
|
||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
toAddr := common.BigToAddress(addr)
|
||||
|
|
@ -679,25 +740,25 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||
if value.Sign() != 0 {
|
||||
gas += params.CallStipend
|
||||
}
|
||||
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
|
||||
ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value)
|
||||
if err != nil {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
||||
}
|
||||
if err == nil || err == errExecutionReverted {
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in evm.callGasTemp.
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
gas := evm.callGasTemp
|
||||
func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||
interpreter.intPool.put(stack.pop())
|
||||
gas := interpreter.evm.callGasTemp
|
||||
// Pop other call parameters.
|
||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
toAddr := common.BigToAddress(addr)
|
||||
|
|
@ -708,96 +769,96 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
|
|||
if value.Sign() != 0 {
|
||||
gas += params.CallStipend
|
||||
}
|
||||
ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
|
||||
ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value)
|
||||
if err != nil {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
||||
}
|
||||
if err == nil || err == errExecutionReverted {
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in evm.callGasTemp.
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
gas := evm.callGasTemp
|
||||
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||
interpreter.intPool.put(stack.pop())
|
||||
gas := interpreter.evm.callGasTemp
|
||||
// Pop other call parameters.
|
||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
toAddr := common.BigToAddress(addr)
|
||||
// Get arguments from the memory.
|
||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||
|
||||
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
|
||||
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas)
|
||||
if err != nil {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
||||
}
|
||||
if err == nil || err == errExecutionReverted {
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
|
||||
interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in evm.callGasTemp.
|
||||
evm.interpreter.intPool.put(stack.pop())
|
||||
gas := evm.callGasTemp
|
||||
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||
interpreter.intPool.put(stack.pop())
|
||||
gas := interpreter.evm.callGasTemp
|
||||
// Pop other call parameters.
|
||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||
toAddr := common.BigToAddress(addr)
|
||||
// Get arguments from the memory.
|
||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||
|
||||
ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
|
||||
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas)
|
||||
if err != nil {
|
||||
stack.push(evm.interpreter.intPool.getZero())
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(evm.interpreter.intPool.get().SetUint64(1))
|
||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
||||
}
|
||||
if err == nil || err == errExecutionReverted {
|
||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
|
||||
evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
|
||||
interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
||||
|
||||
evm.interpreter.intPool.put(offset, size)
|
||||
interpreter.intPool.put(offset, size)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
||||
|
||||
evm.interpreter.intPool.put(offset, size)
|
||||
interpreter.intPool.put(offset, size)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
balance := evm.StateDB.GetBalance(contract.Address())
|
||||
evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
||||
func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
balance := interpreter.evm.StateDB.GetBalance(contract.Address())
|
||||
interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
||||
|
||||
evm.StateDB.Suicide(contract.Address())
|
||||
interpreter.evm.StateDB.Suicide(contract.Address())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -805,7 +866,7 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
|
|||
|
||||
// make log instruction function
|
||||
func makeLog(size int) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
topics := make([]common.Hash, size)
|
||||
mStart, mSize := stack.pop(), stack.pop()
|
||||
for i := 0; i < size; i++ {
|
||||
|
|
@ -813,23 +874,23 @@ func makeLog(size int) executionFunc {
|
|||
}
|
||||
|
||||
d := memory.Get(mStart.Int64(), mSize.Int64())
|
||||
evm.StateDB.AddLog(&types.Log{
|
||||
interpreter.evm.StateDB.AddLog(&types.Log{
|
||||
Address: contract.Address(),
|
||||
Topics: topics,
|
||||
Data: d,
|
||||
// This is a non-consensus field, but assigned here because
|
||||
// core/state doesn't know the current block number.
|
||||
BlockNumber: evm.BlockNumber.Uint64(),
|
||||
BlockNumber: interpreter.evm.BlockNumber.Uint64(),
|
||||
})
|
||||
|
||||
evm.interpreter.intPool.put(mStart, mSize)
|
||||
interpreter.intPool.put(mStart, mSize)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// make push instruction function
|
||||
func makePush(size uint64, pushByteSize int) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
codeLen := len(contract.Code)
|
||||
|
||||
startMin := codeLen
|
||||
|
|
@ -842,7 +903,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
|||
endMin = startMin + pushByteSize
|
||||
}
|
||||
|
||||
integer := evm.interpreter.intPool.get()
|
||||
integer := interpreter.intPool.get()
|
||||
stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize)))
|
||||
|
||||
*pc += size
|
||||
|
|
@ -852,8 +913,8 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
|||
|
||||
// make dup instruction function
|
||||
func makeDup(size int64) executionFunc {
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.dup(evm.interpreter.intPool, int(size))
|
||||
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.dup(interpreter.intPool, int(size))
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -862,7 +923,7 @@ func makeDup(size int64) executionFunc {
|
|||
func makeSwap(size int64) executionFunc {
|
||||
// switch n + 1 otherwise n would be swapped with n
|
||||
size++
|
||||
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.swap(int(size))
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,20 +30,23 @@ type twoOperandTest struct {
|
|||
expected string
|
||||
}
|
||||
|
||||
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
||||
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
pc = uint64(0)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
env.interpreter.intPool = poolOfIntPools.get()
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
for i, test := range tests {
|
||||
x := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
|
||||
shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y))
|
||||
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected))
|
||||
stack.push(x)
|
||||
stack.push(shift)
|
||||
opFn(&pc, env, nil, nil, stack)
|
||||
opFn(&pc, evmInterpreter, nil, nil, stack)
|
||||
actual := stack.pop()
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual)
|
||||
|
|
@ -51,13 +54,13 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
|
|||
// Check pool usage
|
||||
// 1.pool is not allowed to contain anything on the stack
|
||||
// 2.pool is not allowed to contain the same pointers twice
|
||||
if env.interpreter.intPool.pool.len() > 0 {
|
||||
if evmInterpreter.intPool.pool.len() > 0 {
|
||||
|
||||
poolvals := make(map[*big.Int]struct{})
|
||||
poolvals[actual] = struct{}{}
|
||||
|
||||
for env.interpreter.intPool.pool.len() > 0 {
|
||||
key := env.interpreter.intPool.get()
|
||||
for evmInterpreter.intPool.pool.len() > 0 {
|
||||
key := evmInterpreter.intPool.get()
|
||||
if _, exist := poolvals[key]; exist {
|
||||
t.Errorf("Testcase %d, pool contains double-entry", i)
|
||||
}
|
||||
|
|
@ -65,15 +68,18 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
|
|||
}
|
||||
}
|
||||
}
|
||||
poolOfIntPools.put(env.interpreter.intPool)
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func TestByteOp(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
env.interpreter.intPool = poolOfIntPools.get()
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
tests := []struct {
|
||||
v string
|
||||
th uint64
|
||||
|
|
@ -94,13 +100,13 @@ func TestByteOp(t *testing.T) {
|
|||
th := new(big.Int).SetUint64(test.th)
|
||||
stack.push(val)
|
||||
stack.push(th)
|
||||
opByte(&pc, env, nil, nil, stack)
|
||||
opByte(&pc, evmInterpreter, nil, nil, stack)
|
||||
actual := stack.pop()
|
||||
if actual.Cmp(test.expected) != 0 {
|
||||
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual)
|
||||
}
|
||||
}
|
||||
poolOfIntPools.put(env.interpreter.intPool)
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func TestSHL(t *testing.T) {
|
||||
|
|
@ -200,11 +206,14 @@ func TestSLT(t *testing.T) {
|
|||
testTwoOperandOp(t, tests, opSlt)
|
||||
}
|
||||
|
||||
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
||||
func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
// convert args
|
||||
byteArgs := make([][]byte, len(args))
|
||||
for i, arg := range args {
|
||||
|
|
@ -217,7 +226,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contr
|
|||
a := new(big.Int).SetBytes(arg)
|
||||
stack.push(a)
|
||||
}
|
||||
op(&pc, env, nil, nil, stack)
|
||||
op(&pc, evmInterpreter, nil, nil, stack)
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
|
|
@ -435,22 +444,25 @@ func TestOpMstore(t *testing.T) {
|
|||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
env.interpreter.intPool = poolOfIntPools.get()
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
evmInterpreter.intPool = poolOfIntPools.get()
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
||||
if got := common.Bytes2Hex(mem.Get(0, 32)); got != v {
|
||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||
}
|
||||
stack.pushN(big.NewInt(0x1), big.NewInt(0))
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
||||
if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||
t.Fatalf("Mstore failed to overwrite previous value")
|
||||
}
|
||||
poolOfIntPools.put(env.interpreter.intPool)
|
||||
poolOfIntPools.put(evmInterpreter.intPool)
|
||||
}
|
||||
|
||||
func BenchmarkOpMstore(bench *testing.B) {
|
||||
|
|
@ -458,7 +470,10 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
mem.Resize(64)
|
||||
pc := uint64(0)
|
||||
memStart := big.NewInt(0)
|
||||
|
|
@ -467,6 +482,6 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
stack.pushN(value, memStart)
|
||||
opMstore(&pc, env, nil, mem, stack)
|
||||
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,30 @@ type Config struct {
|
|||
// passed environment to query external sources for state information.
|
||||
// The Interpreter will run the byte code VM based on the passed
|
||||
// configuration.
|
||||
type Interpreter struct {
|
||||
type Interpreter interface {
|
||||
// Run loops and evaluates the contract's code with the given input data and returns
|
||||
// the return byte-slice and an error if one occurred.
|
||||
Run(contract *Contract, input []byte) ([]byte, error)
|
||||
// CanRun tells if the contract, passed as an argument, can be
|
||||
// run by the current interpreter. This is meant so that the
|
||||
// caller can do something like:
|
||||
//
|
||||
// ```golang
|
||||
// for _, interpreter := range interpreters {
|
||||
// if interpreter.CanRun(contract.code) {
|
||||
// interpreter.Run(contract.code, input)
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
CanRun([]byte) bool
|
||||
// IsReadOnly reports if the interpreter is in read only mode.
|
||||
IsReadOnly() bool
|
||||
// SetReadOnly sets (or unsets) read only mode in the interpreter.
|
||||
SetReadOnly(bool)
|
||||
}
|
||||
|
||||
// EVMInterpreter represents an EVM interpreter
|
||||
type EVMInterpreter struct {
|
||||
evm *EVM
|
||||
cfg Config
|
||||
gasTable params.GasTable
|
||||
|
|
@ -55,8 +78,8 @@ type Interpreter struct {
|
|||
returnData []byte // Last CALL's return data for subsequent reuse
|
||||
}
|
||||
|
||||
// NewInterpreter returns a new instance of the Interpreter.
|
||||
func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
|
||||
// NewEVMInterpreter returns a new instance of the Interpreter.
|
||||
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
||||
// We use the STOP instruction whether to see
|
||||
// the jump table was initialised. If it was not
|
||||
// we'll set the default jump table.
|
||||
|
|
@ -73,14 +96,14 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
return &Interpreter{
|
||||
return &EVMInterpreter{
|
||||
evm: evm,
|
||||
cfg: cfg,
|
||||
gasTable: evm.ChainConfig().GasTable(evm.BlockNumber),
|
||||
}
|
||||
}
|
||||
|
||||
func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
||||
func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
||||
if in.evm.chainRules.IsByzantium {
|
||||
if in.readOnly {
|
||||
// If the interpreter is operating in readonly mode, make sure no
|
||||
|
|
@ -102,7 +125,7 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
|
|||
// It's important to note that any errors returned by the interpreter should be
|
||||
// considered a revert-and-consume-all-gas operation except for
|
||||
// errExecutionReverted which means revert-and-keep-gas-left.
|
||||
func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||
func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||
if in.intPool == nil {
|
||||
in.intPool = poolOfIntPools.get()
|
||||
defer func() {
|
||||
|
|
@ -209,7 +232,7 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
|
|||
}
|
||||
|
||||
// execute the operation
|
||||
res, err := operation.execute(&pc, in.evm, contract, mem, stack)
|
||||
res, err := operation.execute(&pc, in, contract, mem, stack)
|
||||
// verifyPool is a build flag. Pool verification makes sure the integrity
|
||||
// of the integer pool by comparing values to a default value.
|
||||
if verifyPool {
|
||||
|
|
@ -234,3 +257,19 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CanRun tells if the contract, passed as an argument, can be
|
||||
// run by the current interpreter.
|
||||
func (in *EVMInterpreter) CanRun(code []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsReadOnly reports if the interpreter is in read only mode.
|
||||
func (in *EVMInterpreter) IsReadOnly() bool {
|
||||
return in.readOnly
|
||||
}
|
||||
|
||||
// SetReadOnly sets (or unsets) read only mode in the interpreter.
|
||||
func (in *EVMInterpreter) SetReadOnly(ro bool) {
|
||||
in.readOnly = ro
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
|
||||
executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
|
||||
gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
|
||||
stackValidationFunc func(*Stack) error
|
||||
memorySizeFunc func(*Stack) *big.Int
|
||||
|
|
@ -80,6 +80,21 @@ func newConstantinopleInstructionSet() [256]operation {
|
|||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[EXTCODEHASH] = operation{
|
||||
execute: opExtCodeHash,
|
||||
gasCost: gasExtCodeHash,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[CREATE2] = operation{
|
||||
execute: opCreate2,
|
||||
gasCost: gasCreate2,
|
||||
validateStack: makeStackFunc(4, 1),
|
||||
memorySize: memoryCreate2,
|
||||
valid: true,
|
||||
writes: true,
|
||||
returns: true,
|
||||
}
|
||||
return instructionSet
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int {
|
|||
return calcMemSize(stack.Back(1), stack.Back(2))
|
||||
}
|
||||
|
||||
func memoryCreate2(stack *Stack) *big.Int {
|
||||
return calcMemSize(stack.Back(1), stack.Back(2))
|
||||
}
|
||||
|
||||
func memoryCall(stack *Stack) *big.Int {
|
||||
x := calcMemSize(stack.Back(5), stack.Back(6))
|
||||
y := calcMemSize(stack.Back(3), stack.Back(4))
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ const (
|
|||
EXTCODECOPY
|
||||
RETURNDATASIZE
|
||||
RETURNDATACOPY
|
||||
EXTCODEHASH
|
||||
)
|
||||
|
||||
// 0x40 range - block operations.
|
||||
|
|
@ -209,6 +210,7 @@ const (
|
|||
CALLCODE
|
||||
RETURN
|
||||
DELEGATECALL
|
||||
CREATE2
|
||||
STATICCALL = 0xfa
|
||||
|
||||
REVERT = 0xfd
|
||||
|
|
@ -266,6 +268,7 @@ var opCodeToString = map[OpCode]string{
|
|||
EXTCODECOPY: "EXTCODECOPY",
|
||||
RETURNDATASIZE: "RETURNDATASIZE",
|
||||
RETURNDATACOPY: "RETURNDATACOPY",
|
||||
EXTCODEHASH: "EXTCODEHASH",
|
||||
|
||||
// 0x40 range - block operations.
|
||||
BLOCKHASH: "BLOCKHASH",
|
||||
|
|
@ -370,6 +373,7 @@ var opCodeToString = map[OpCode]string{
|
|||
RETURN: "RETURN",
|
||||
CALLCODE: "CALLCODE",
|
||||
DELEGATECALL: "DELEGATECALL",
|
||||
CREATE2: "CREATE2",
|
||||
STATICCALL: "STATICCALL",
|
||||
REVERT: "REVERT",
|
||||
SELFDESTRUCT: "SELFDESTRUCT",
|
||||
|
|
@ -433,6 +437,7 @@ var stringToOp = map[string]OpCode{
|
|||
"EXTCODECOPY": EXTCODECOPY,
|
||||
"RETURNDATASIZE": RETURNDATASIZE,
|
||||
"RETURNDATACOPY": RETURNDATACOPY,
|
||||
"EXTCODEHASH": EXTCODEHASH,
|
||||
"BLOCKHASH": BLOCKHASH,
|
||||
"COINBASE": COINBASE,
|
||||
"TIMESTAMP": TIMESTAMP,
|
||||
|
|
@ -521,6 +526,7 @@ var stringToOp = map[string]OpCode{
|
|||
"LOG3": LOG3,
|
||||
"LOG4": LOG4,
|
||||
"CREATE": CREATE,
|
||||
"CREATE2": CREATE2,
|
||||
"CALL": CALL,
|
||||
"RETURN": RETURN,
|
||||
"CALLCODE": CALLCODE,
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ func CreateAddress(b common.Address, nonce uint64) common.Address {
|
|||
return common.BytesToAddress(Keccak256(data)[12:])
|
||||
}
|
||||
|
||||
// CreateAddress2 creates an ethereum address given the address bytes, initial
|
||||
// contract code and a salt.
|
||||
func CreateAddress2(b common.Address, salt common.Hash, code []byte) common.Address {
|
||||
return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt.Bytes(), code)[12:])
|
||||
}
|
||||
|
||||
// ToECDSA creates a private key with the given D value.
|
||||
func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
|
||||
return toECDSA(d, true)
|
||||
|
|
|
|||
31
crypto/secp256k1/LICENSE
Normal file
31
crypto/secp256k1/LICENSE
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
Copyright (c) 2010 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2011 ThePiachu. All rights reserved.
|
||||
Copyright (c) 2015 Jeffrey Wilcke. All rights reserved.
|
||||
Copyright (c) 2015 Felix Lange. All rights reserved.
|
||||
Copyright (c) 2015 Gustav Simonsson. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holder. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Copyright 2011 ThePiachu. All rights reserved.
|
||||
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
|
@ -35,8 +36,6 @@ import (
|
|||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
/*
|
||||
|
|
@ -45,6 +44,27 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned
|
|||
*/
|
||||
import "C"
|
||||
|
||||
const (
|
||||
// number of bits in a big.Word
|
||||
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
|
||||
// number of bytes in a big.Word
|
||||
wordBytes = wordBits / 8
|
||||
)
|
||||
|
||||
// readBits encodes the absolute value of bigint as big-endian bytes. Callers
|
||||
// must ensure that buf has enough space. If buf is too short the result will
|
||||
// be incomplete.
|
||||
func readBits(bigint *big.Int, buf []byte) {
|
||||
i := len(buf)
|
||||
for _, d := range bigint.Bits() {
|
||||
for j := 0; j < wordBytes && i > 0; j++ {
|
||||
i--
|
||||
buf[i] = byte(d)
|
||||
d >>= 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This code is from https://github.com/ThePiachu/GoBit and implements
|
||||
// several Koblitz elliptic curves over prime fields.
|
||||
//
|
||||
|
|
@ -231,8 +251,9 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
|
|||
|
||||
// Do the multiplication in C, updating point.
|
||||
point := make([]byte, 64)
|
||||
math.ReadBits(Bx, point[:32])
|
||||
math.ReadBits(By, point[32:])
|
||||
readBits(Bx, point[:32])
|
||||
readBits(By, point[32:])
|
||||
|
||||
pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
|
||||
scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
|
||||
res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr)
|
||||
|
|
@ -264,8 +285,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
|
|||
byteLen := (BitCurve.BitSize + 7) >> 3
|
||||
ret := make([]byte, 1+2*byteLen)
|
||||
ret[0] = 4 // uncompressed point flag
|
||||
math.ReadBits(x, ret[1:1+byteLen])
|
||||
math.ReadBits(y, ret[1+byteLen:])
|
||||
readBits(x, ret[1:1+byteLen])
|
||||
readBits(y, ret[1+byteLen:])
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
@ -290,11 +311,11 @@ func init() {
|
|||
// See SEC 2 section 2.7.1
|
||||
// curve parameters taken from:
|
||||
// http://www.secg.org/collateral/sec2_final.pdf
|
||||
theCurve.P = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")
|
||||
theCurve.N = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
|
||||
theCurve.B = math.MustParseBig256("0x0000000000000000000000000000000000000000000000000000000000000007")
|
||||
theCurve.Gx = math.MustParseBig256("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
|
||||
theCurve.Gy = math.MustParseBig256("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
|
||||
theCurve.P, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 0)
|
||||
theCurve.N, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 0)
|
||||
theCurve.B, _ = new(big.Int).SetString("0x0000000000000000000000000000000000000000000000000000000000000007", 0)
|
||||
theCurve.Gx, _ = new(big.Int).SetString("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 0)
|
||||
theCurve.Gy, _ = new(big.Int).SetString("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 0)
|
||||
theCurve.BitSize = 256
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
// secp256k1_context_create_sign_verify creates a context for signing and signature verification.
|
||||
static secp256k1_context* secp256k1_context_create_sign_verify() {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package secp256k1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
// Package secp256k1 wraps the bitcoin secp256k1 C library.
|
||||
package secp256k1
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package secp256k1
|
||||
|
||||
|
|
@ -22,10 +10,8 @@ import (
|
|||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||
)
|
||||
|
||||
const TestCount = 1000
|
||||
|
|
@ -36,11 +22,24 @@ func generateKeyPair() (pubkey, privkey []byte) {
|
|||
panic(err)
|
||||
}
|
||||
pubkey = elliptic.Marshal(S256(), key.X, key.Y)
|
||||
return pubkey, math.PaddedBigBytes(key.D, 32)
|
||||
|
||||
privkey = make([]byte, 32)
|
||||
blob := key.D.Bytes()
|
||||
copy(privkey[32-len(blob):], blob)
|
||||
|
||||
return pubkey, privkey
|
||||
}
|
||||
|
||||
func csprngEntropy(n int) []byte {
|
||||
buf := make([]byte, n)
|
||||
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
|
||||
panic("reading from crypto/rand failed: " + err.Error())
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func randSig() []byte {
|
||||
sig := randentropy.GetEntropyCSPRNG(65)
|
||||
sig := csprngEntropy(65)
|
||||
sig[32] &= 0x70
|
||||
sig[64] %= 4
|
||||
return sig
|
||||
|
|
@ -63,7 +62,7 @@ func compactSigCheck(t *testing.T, sig []byte) {
|
|||
|
||||
func TestSignatureValidity(t *testing.T) {
|
||||
pubkey, seckey := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
sig, err := Sign(msg, seckey)
|
||||
if err != nil {
|
||||
t.Errorf("signature error: %s", err)
|
||||
|
|
@ -86,7 +85,7 @@ func TestSignatureValidity(t *testing.T) {
|
|||
|
||||
func TestInvalidRecoveryID(t *testing.T) {
|
||||
_, seckey := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
sig[64] = 99
|
||||
_, err := RecoverPubkey(msg, sig)
|
||||
|
|
@ -97,7 +96,7 @@ func TestInvalidRecoveryID(t *testing.T) {
|
|||
|
||||
func TestSignAndRecover(t *testing.T) {
|
||||
pubkey1, seckey := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
sig, err := Sign(msg, seckey)
|
||||
if err != nil {
|
||||
t.Errorf("signature error: %s", err)
|
||||
|
|
@ -148,7 +147,7 @@ func TestRandomMessagesWithRandomKeys(t *testing.T) {
|
|||
func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) {
|
||||
for i := 0; i < TestCount; i++ {
|
||||
pubkey1, seckey := keys()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
sig, err := Sign(msg, seckey)
|
||||
if err != nil {
|
||||
t.Fatalf("signature error: %s", err)
|
||||
|
|
@ -176,7 +175,7 @@ func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)
|
|||
|
||||
func TestRecoveryOfRandomSignature(t *testing.T) {
|
||||
pubkey1, _ := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
|
||||
for i := 0; i < TestCount; i++ {
|
||||
// recovery can sometimes work, but if so should always give wrong pubkey
|
||||
|
|
@ -189,11 +188,11 @@ func TestRecoveryOfRandomSignature(t *testing.T) {
|
|||
|
||||
func TestRandomMessagesAgainstValidSig(t *testing.T) {
|
||||
pubkey1, seckey := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
|
||||
for i := 0; i < TestCount; i++ {
|
||||
msg = randentropy.GetEntropyCSPRNG(32)
|
||||
msg = csprngEntropy(32)
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
// recovery can sometimes work, but if so should always give wrong pubkey
|
||||
if bytes.Equal(pubkey1, pubkey2) {
|
||||
|
|
@ -219,7 +218,7 @@ func TestRecoverSanity(t *testing.T) {
|
|||
|
||||
func BenchmarkSign(b *testing.B) {
|
||||
_, seckey := generateKeyPair()
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
@ -228,7 +227,7 @@ func BenchmarkSign(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkRecover(b *testing.B) {
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
msg := csprngEntropy(32)
|
||||
_, seckey := generateKeyPair()
|
||||
sig, _ := Sign(msg, seckey)
|
||||
b.ResetTimer()
|
||||
|
|
|
|||
17638
dashboard/assets.go
17638
dashboard/assets.go
File diff suppressed because one or more lines are too long
|
|
@ -68,4 +68,4 @@ export const styles = {
|
|||
light: {
|
||||
color: 'rgba(255, 255, 255, 0.54)',
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const styles = {
|
|||
body: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
height: '92%',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -37,6 +37,7 @@ export type Props = {
|
|||
active: string,
|
||||
content: Content,
|
||||
shouldUpdate: Object,
|
||||
send: string => void,
|
||||
};
|
||||
|
||||
// Body renders the body of the dashboard.
|
||||
|
|
@ -52,6 +53,7 @@ class Body extends Component<Props> {
|
|||
active={this.props.active}
|
||||
content={this.props.content}
|
||||
shouldUpdate={this.props.shouldUpdate}
|
||||
send={this.props.send}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export type Props = {
|
|||
class CustomTooltip extends Component<Props> {
|
||||
render() {
|
||||
const {active, payload, tooltip} = this.props;
|
||||
if (!active || typeof tooltip !== 'function') {
|
||||
if (!active || typeof tooltip !== 'function' || !Array.isArray(payload) || payload.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return tooltip(payload[0].value);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import Header from './Header';
|
|||
import Body from './Body';
|
||||
import {MENU} from '../common';
|
||||
import type {Content} from '../types/content';
|
||||
import {inserter as logInserter} from './Logs';
|
||||
|
||||
// deepUpdate updates an object corresponding to the given update data, which has
|
||||
// the shape of the same structure as the original object. updater also has the same
|
||||
|
|
@ -75,8 +76,11 @@ const appender = <T>(limit: number, mapper = replacer) => (update: Array<T>, pre
|
|||
...update.map(sample => mapper(sample)),
|
||||
].slice(-limit);
|
||||
|
||||
// defaultContent is the initial value of the state content.
|
||||
const defaultContent: Content = {
|
||||
// defaultContent returns the initial value of the state content. Needs to be a function in order to
|
||||
// instantiate the object again, because it is used by the state, and isn't automatically cleaned
|
||||
// when a new connection is established. The state is mutated during the update in order to avoid
|
||||
// the execution of unnecessary operations (e.g. copy of the log array).
|
||||
const defaultContent: () => Content = () => ({
|
||||
general: {
|
||||
version: null,
|
||||
commit: null,
|
||||
|
|
@ -96,9 +100,13 @@ const defaultContent: Content = {
|
|||
diskWrite: [],
|
||||
},
|
||||
logs: {
|
||||
log: [],
|
||||
chunks: [],
|
||||
endTop: false,
|
||||
endBottom: true,
|
||||
topChanged: 0,
|
||||
bottomChanged: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// updaters contains the state updater functions for each path of the state.
|
||||
//
|
||||
|
|
@ -122,9 +130,7 @@ const updaters = {
|
|||
diskRead: appender(200),
|
||||
diskWrite: appender(200),
|
||||
},
|
||||
logs: {
|
||||
log: appender(200),
|
||||
},
|
||||
logs: logInserter(5),
|
||||
};
|
||||
|
||||
// styles contains the constant styles of the component.
|
||||
|
|
@ -155,6 +161,7 @@ type State = {
|
|||
sideBar: boolean, // true if the sidebar is opened
|
||||
content: Content, // the visualized data
|
||||
shouldUpdate: Object, // labels for the components, which need to re-render based on the incoming message
|
||||
server: ?WebSocket,
|
||||
};
|
||||
|
||||
// Dashboard is the main component, which renders the whole page, makes connection with the server and
|
||||
|
|
@ -165,8 +172,9 @@ class Dashboard extends Component<Props, State> {
|
|||
this.state = {
|
||||
active: MENU.get('home').id,
|
||||
sideBar: true,
|
||||
content: defaultContent,
|
||||
content: defaultContent(),
|
||||
shouldUpdate: {},
|
||||
server: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +189,7 @@ class Dashboard extends Component<Props, State> {
|
|||
// PROD is defined by webpack.
|
||||
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`);
|
||||
server.onopen = () => {
|
||||
this.setState({content: defaultContent, shouldUpdate: {}});
|
||||
this.setState({content: defaultContent(), shouldUpdate: {}, server});
|
||||
};
|
||||
server.onmessage = (event) => {
|
||||
const msg: $Shape<Content> = JSON.parse(event.data);
|
||||
|
|
@ -192,10 +200,18 @@ class Dashboard extends Component<Props, State> {
|
|||
this.update(msg);
|
||||
};
|
||||
server.onclose = () => {
|
||||
this.setState({server: null});
|
||||
setTimeout(this.reconnect, 3000);
|
||||
};
|
||||
};
|
||||
|
||||
// send sends a message to the server, which can be accessed only through this function for safety reasons.
|
||||
send = (msg: string) => {
|
||||
if (this.state.server != null) {
|
||||
this.state.server.send(msg);
|
||||
}
|
||||
};
|
||||
|
||||
// update updates the content corresponding to the incoming message.
|
||||
update = (msg: $Shape<Content>) => {
|
||||
this.setState(prevState => ({
|
||||
|
|
@ -226,6 +242,7 @@ class Dashboard extends Component<Props, State> {
|
|||
active={this.state.active}
|
||||
content={this.state.content}
|
||||
shouldUpdate={this.state.shouldUpdate}
|
||||
send={this.send}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,16 @@ import Icon from 'material-ui/Icon';
|
|||
import MenuIcon from 'material-ui-icons/Menu';
|
||||
import Typography from 'material-ui/Typography';
|
||||
|
||||
// styles contains the constant styles of the component.
|
||||
const styles = {
|
||||
header: {
|
||||
height: '8%',
|
||||
},
|
||||
toolbar: {
|
||||
height: '100%',
|
||||
},
|
||||
};
|
||||
|
||||
// themeStyles returns the styles generated from the theme for the component.
|
||||
const themeStyles = (theme: Object) => ({
|
||||
header: {
|
||||
|
|
@ -54,8 +64,8 @@ class Header extends Component<Props> {
|
|||
const {classes} = this.props;
|
||||
|
||||
return (
|
||||
<AppBar position='static' className={classes.header}>
|
||||
<Toolbar className={classes.toolbar}>
|
||||
<AppBar position='static' className={classes.header} style={styles.header}>
|
||||
<Toolbar className={classes.toolbar} style={styles.toolbar}>
|
||||
<IconButton onClick={this.props.switchSideBar}>
|
||||
<Icon>
|
||||
<MenuIcon />
|
||||
|
|
|
|||
326
dashboard/assets/components/Logs.jsx
Normal file
326
dashboard/assets/components/Logs.jsx
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
// @flow
|
||||
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, {Component} from 'react';
|
||||
|
||||
import List, {ListItem} from 'material-ui/List';
|
||||
import escapeHtml from 'escape-html';
|
||||
import type {Record, Content, LogsMessage, Logs as LogsType} from '../types/content';
|
||||
|
||||
// requestBand says how wide is the top/bottom zone, eg. 0.1 means 10% of the container height.
|
||||
const requestBand = 0.05;
|
||||
|
||||
// fieldPadding is a global map with maximum field value lengths seen until now
|
||||
// to allow padding log contexts in a bit smarter way.
|
||||
const fieldPadding = new Map();
|
||||
|
||||
// createChunk creates an HTML formatted object, which displays the given array similarly to
|
||||
// the server side terminal.
|
||||
const createChunk = (records: Array<Record>) => {
|
||||
let content = '';
|
||||
records.forEach((record) => {
|
||||
const {t, ctx} = record;
|
||||
let {lvl, msg} = record;
|
||||
let color = '#ce3c23';
|
||||
switch (lvl) {
|
||||
case 'trace':
|
||||
case 'trce':
|
||||
lvl = 'TRACE';
|
||||
color = '#3465a4';
|
||||
break;
|
||||
case 'debug':
|
||||
case 'dbug':
|
||||
lvl = 'DEBUG';
|
||||
color = '#3d989b';
|
||||
break;
|
||||
case 'info':
|
||||
lvl = 'INFO ';
|
||||
color = '#4c8f0f';
|
||||
break;
|
||||
case 'warn':
|
||||
lvl = 'WARN ';
|
||||
color = '#b79a22';
|
||||
break;
|
||||
case 'error':
|
||||
case 'eror':
|
||||
lvl = 'ERROR';
|
||||
color = '#754b70';
|
||||
break;
|
||||
case 'crit':
|
||||
lvl = 'CRIT ';
|
||||
color = '#ce3c23';
|
||||
break;
|
||||
default:
|
||||
lvl = '';
|
||||
}
|
||||
const time = new Date(t);
|
||||
if (lvl === '' || !(time instanceof Date) || isNaN(time) || typeof msg !== 'string' || !Array.isArray(ctx)) {
|
||||
content += '<span style="color:#ce3c23">Invalid log record</span><br />';
|
||||
return;
|
||||
}
|
||||
if (ctx.length > 0) {
|
||||
msg += ' '.repeat(Math.max(40 - msg.length, 0));
|
||||
}
|
||||
const month = `0${time.getMonth() + 1}`.slice(-2);
|
||||
const date = `0${time.getDate()}`.slice(-2);
|
||||
const hours = `0${time.getHours()}`.slice(-2);
|
||||
const minutes = `0${time.getMinutes()}`.slice(-2);
|
||||
const seconds = `0${time.getSeconds()}`.slice(-2);
|
||||
content += `<span style="color:${color}">${lvl}</span>[${month}-${date}|${hours}:${minutes}:${seconds}] ${msg}`;
|
||||
|
||||
for (let i = 0; i < ctx.length; i += 2) {
|
||||
const key = escapeHtml(ctx[i]);
|
||||
const val = escapeHtml(ctx[i + 1]);
|
||||
let padding = fieldPadding.get(key);
|
||||
if (typeof padding !== 'number' || padding < val.length) {
|
||||
padding = val.length;
|
||||
fieldPadding.set(key, padding);
|
||||
}
|
||||
let p = '';
|
||||
if (i < ctx.length - 2) {
|
||||
p = ' '.repeat(padding - val.length);
|
||||
}
|
||||
content += ` <span style="color:${color}">${key}</span>=${val}${p}`;
|
||||
}
|
||||
content += '<br />';
|
||||
});
|
||||
return content;
|
||||
};
|
||||
|
||||
// ADDED, SAME and REMOVED are used to track the change of the log chunk array.
|
||||
// The scroll position is set using these values.
|
||||
const ADDED = 1;
|
||||
const SAME = 0;
|
||||
const REMOVED = -1;
|
||||
|
||||
// inserter is a state updater function for the main component, which inserts the new log chunk into the chunk array.
|
||||
// limit is the maximum length of the chunk array, used in order to prevent the browser from OOM.
|
||||
export const inserter = (limit: number) => (update: LogsMessage, prev: LogsType) => {
|
||||
prev.topChanged = SAME;
|
||||
prev.bottomChanged = SAME;
|
||||
if (!Array.isArray(update.chunk) || update.chunk.length < 1) {
|
||||
return prev;
|
||||
}
|
||||
if (!Array.isArray(prev.chunks)) {
|
||||
prev.chunks = [];
|
||||
}
|
||||
const content = createChunk(update.chunk);
|
||||
if (!update.source) {
|
||||
// In case of stream chunk.
|
||||
if (!prev.endBottom) {
|
||||
return prev;
|
||||
}
|
||||
if (prev.chunks.length < 1) {
|
||||
// This should never happen, because the first chunk is always a non-stream chunk.
|
||||
return [{content, name: '00000000000000.log'}];
|
||||
}
|
||||
prev.chunks[prev.chunks.length - 1].content += content;
|
||||
prev.bottomChanged = ADDED;
|
||||
return prev;
|
||||
}
|
||||
const chunk = {
|
||||
content,
|
||||
name: update.source.name,
|
||||
};
|
||||
if (prev.chunks.length > 0 && update.source.name < prev.chunks[0].name) {
|
||||
if (update.source.last) {
|
||||
prev.endTop = true;
|
||||
}
|
||||
if (prev.chunks.length >= limit) {
|
||||
prev.endBottom = false;
|
||||
prev.chunks.splice(limit - 1, prev.chunks.length - limit + 1);
|
||||
prev.bottomChanged = REMOVED;
|
||||
}
|
||||
prev.chunks = [chunk, ...prev.chunks];
|
||||
prev.topChanged = ADDED;
|
||||
return prev;
|
||||
}
|
||||
if (update.source.last) {
|
||||
prev.endBottom = true;
|
||||
}
|
||||
if (prev.chunks.length >= limit) {
|
||||
prev.endTop = false;
|
||||
prev.chunks.splice(0, prev.chunks.length - limit + 1);
|
||||
prev.topChanged = REMOVED;
|
||||
}
|
||||
prev.chunks = [...prev.chunks, chunk];
|
||||
prev.bottomChanged = ADDED;
|
||||
return prev;
|
||||
};
|
||||
|
||||
// styles contains the constant styles of the component.
|
||||
const styles = {
|
||||
logListItem: {
|
||||
padding: 0,
|
||||
lineHeight: 1.231,
|
||||
},
|
||||
logChunk: {
|
||||
color: 'white',
|
||||
fontFamily: 'monospace',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 0,
|
||||
},
|
||||
waitMsg: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
};
|
||||
|
||||
export type Props = {
|
||||
container: Object,
|
||||
content: Content,
|
||||
shouldUpdate: Object,
|
||||
send: string => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
requestAllowed: boolean,
|
||||
};
|
||||
|
||||
// Logs renders the log page.
|
||||
class Logs extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.content = React.createRef();
|
||||
this.state = {
|
||||
requestAllowed: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {container} = this.props;
|
||||
if (typeof container === 'undefined') {
|
||||
return;
|
||||
}
|
||||
container.scrollTop = container.scrollHeight - container.clientHeight;
|
||||
const {logs} = this.props.content;
|
||||
if (typeof this.content === 'undefined' || logs.chunks.length < 1) {
|
||||
return;
|
||||
}
|
||||
if (this.content.clientHeight < container.clientHeight && !logs.endTop) {
|
||||
this.sendRequest(logs.chunks[0].name, true);
|
||||
}
|
||||
}
|
||||
|
||||
// onScroll is triggered by the parent component's scroll event, and sends requests if the scroll position is
|
||||
// at the top or at the bottom.
|
||||
onScroll = () => {
|
||||
if (!this.state.requestAllowed || typeof this.content === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const {logs} = this.props.content;
|
||||
if (logs.chunks.length < 1) {
|
||||
return;
|
||||
}
|
||||
if (this.atTop() && !logs.endTop) {
|
||||
this.sendRequest(logs.chunks[0].name, true);
|
||||
} else if (this.atBottom() && !logs.endBottom) {
|
||||
this.sendRequest(logs.chunks[logs.chunks.length - 1].name, false);
|
||||
}
|
||||
};
|
||||
|
||||
sendRequest = (name: string, past: boolean) => {
|
||||
this.setState({requestAllowed: false});
|
||||
this.props.send(JSON.stringify({
|
||||
Logs: {
|
||||
Name: name,
|
||||
Past: past,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
// atTop checks if the scroll position it at the top of the container.
|
||||
atTop = () => this.props.container.scrollTop <= this.props.container.scrollHeight * requestBand;
|
||||
|
||||
// atBottom checks if the scroll position it at the bottom of the container.
|
||||
atBottom = () => {
|
||||
const {container} = this.props;
|
||||
return container.scrollHeight - container.scrollTop <=
|
||||
container.clientHeight + container.scrollHeight * requestBand;
|
||||
};
|
||||
|
||||
// beforeUpdate is called by the parent component, saves the previous scroll position
|
||||
// and the height of the first log chunk, which can be deleted during the insertion.
|
||||
beforeUpdate = () => {
|
||||
let firstHeight = 0;
|
||||
let chunkList = this.content.children[1];
|
||||
if (chunkList && chunkList.children[0]) {
|
||||
firstHeight = chunkList.children[0].clientHeight;
|
||||
}
|
||||
return {
|
||||
scrollTop: this.props.container.scrollTop,
|
||||
firstHeight,
|
||||
};
|
||||
};
|
||||
|
||||
// didUpdate is called by the parent component, which provides the container. Sends the first request if the
|
||||
// visible part of the container isn't full, and resets the scroll position in order to avoid jumping when a
|
||||
// chunk is inserted or removed.
|
||||
didUpdate = (prevProps, prevState, snapshot) => {
|
||||
if (typeof this.props.shouldUpdate.logs === 'undefined' || typeof this.content === 'undefined' || snapshot === null) {
|
||||
return;
|
||||
}
|
||||
const {logs} = this.props.content;
|
||||
const {container} = this.props;
|
||||
if (typeof container === 'undefined' || logs.chunks.length < 1) {
|
||||
return;
|
||||
}
|
||||
if (this.content.clientHeight < container.clientHeight) {
|
||||
// Only enters here at the beginning, when there aren't enough logs to fill the container
|
||||
// and the scroll bar doesn't appear.
|
||||
if (!logs.endTop) {
|
||||
this.sendRequest(logs.chunks[0].name, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let {scrollTop} = snapshot;
|
||||
if (logs.topChanged === ADDED) {
|
||||
// It would be safer to use a ref to the list, but ref doesn't work well with HOCs.
|
||||
scrollTop += this.content.children[1].children[0].clientHeight;
|
||||
} else if (logs.bottomChanged === ADDED) {
|
||||
if (logs.topChanged === REMOVED) {
|
||||
scrollTop -= snapshot.firstHeight;
|
||||
} else if (this.atBottom() && logs.endBottom) {
|
||||
scrollTop = container.scrollHeight - container.clientHeight;
|
||||
}
|
||||
}
|
||||
container.scrollTop = scrollTop;
|
||||
this.setState({requestAllowed: true});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div ref={(ref) => { this.content = ref; }}>
|
||||
<div style={styles.waitMsg}>
|
||||
{this.props.content.logs.endTop ? 'No more logs.' : 'Waiting for server...'}
|
||||
</div>
|
||||
<List>
|
||||
{this.props.content.logs.chunks.map((c, index) => (
|
||||
<ListItem style={styles.logListItem} key={index}>
|
||||
<div style={styles.logChunk} dangerouslySetInnerHTML={{__html: c.content}} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
{this.props.content.logs.endBottom || <div style={styles.waitMsg}>Waiting for server...</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Logs;
|
||||
|
|
@ -21,6 +21,7 @@ import React, {Component} from 'react';
|
|||
import withStyles from 'material-ui/styles/withStyles';
|
||||
|
||||
import {MENU} from '../common';
|
||||
import Logs from './Logs';
|
||||
import Footer from './Footer';
|
||||
import type {Content} from '../types/content';
|
||||
|
||||
|
|
@ -50,10 +51,36 @@ export type Props = {
|
|||
active: string,
|
||||
content: Content,
|
||||
shouldUpdate: Object,
|
||||
send: string => void,
|
||||
};
|
||||
|
||||
// Main renders the chosen content.
|
||||
class Main extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.container = React.createRef();
|
||||
this.content = React.createRef();
|
||||
}
|
||||
|
||||
getSnapshotBeforeUpdate() {
|
||||
if (this.content && typeof this.content.beforeUpdate === 'function') {
|
||||
return this.content.beforeUpdate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (this.content && typeof this.content.didUpdate === 'function') {
|
||||
this.content.didUpdate(prevProps, prevState, snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
onScroll = () => {
|
||||
if (this.content && typeof this.content.onScroll === 'function') {
|
||||
this.content.onScroll();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
classes, active, content, shouldUpdate,
|
||||
|
|
@ -69,12 +96,27 @@ class Main extends Component<Props> {
|
|||
children = <div>Work in progress.</div>;
|
||||
break;
|
||||
case MENU.get('logs').id:
|
||||
children = <div>{content.logs.log.map((log, index) => <div key={index}>{log}</div>)}</div>;
|
||||
children = (
|
||||
<Logs
|
||||
ref={(ref) => { this.content = ref; }}
|
||||
container={this.container}
|
||||
send={this.props.send}
|
||||
content={this.props.content}
|
||||
shouldUpdate={shouldUpdate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={styles.wrapper}>
|
||||
<div className={classes.content} style={styles.content}>{children}</div>
|
||||
<div
|
||||
className={classes.content}
|
||||
style={styles.content}
|
||||
ref={(ref) => { this.container = ref; }}
|
||||
onScroll={this.onScroll}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
<Footer
|
||||
general={content.general}
|
||||
system={content.system}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
::-webkit-scrollbar-thumb {
|
||||
background: #212121;
|
||||
}
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="height: 100%; margin: 0">
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"babel-runtime": "^6.26.0",
|
||||
"classnames": "^2.2.5",
|
||||
"css-loader": "^0.28.9",
|
||||
"escape-html": "^1.0.3",
|
||||
"eslint": "^4.16.0",
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-loader": "^2.0.0",
|
||||
|
|
|
|||
|
|
@ -65,6 +65,32 @@ export type System = {
|
|||
diskWrite: ChartEntries,
|
||||
};
|
||||
|
||||
export type Logs = {
|
||||
log: Array<string>,
|
||||
export type Record = {
|
||||
t: string,
|
||||
lvl: Object,
|
||||
msg: string,
|
||||
ctx: Array<string>
|
||||
};
|
||||
|
||||
export type Chunk = {
|
||||
content: string,
|
||||
name: string,
|
||||
};
|
||||
|
||||
export type Logs = {
|
||||
chunks: Array<Chunk>,
|
||||
endTop: boolean,
|
||||
endBottom: boolean,
|
||||
topChanged: number,
|
||||
bottomChanged: number,
|
||||
};
|
||||
|
||||
export type LogsMessage = {
|
||||
source: ?LogFile,
|
||||
chunk: Array<Record>,
|
||||
};
|
||||
|
||||
export type LogFile = {
|
||||
name: string,
|
||||
last: string,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,70 +2,77 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/code-frame@7.0.0-beta.40", "@babel/code-frame@^7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6"
|
||||
"@babel/code-frame@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9"
|
||||
dependencies:
|
||||
"@babel/highlight" "7.0.0-beta.40"
|
||||
"@babel/highlight" "7.0.0-beta.44"
|
||||
|
||||
"@babel/generator@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea"
|
||||
"@babel/generator@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42"
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.2.0"
|
||||
source-map "^0.5.0"
|
||||
trim-right "^1.0.1"
|
||||
|
||||
"@babel/helper-function-name@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6"
|
||||
"@babel/helper-function-name@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd"
|
||||
dependencies:
|
||||
"@babel/helper-get-function-arity" "7.0.0-beta.40"
|
||||
"@babel/template" "7.0.0-beta.40"
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
"@babel/helper-get-function-arity" "7.0.0-beta.44"
|
||||
"@babel/template" "7.0.0-beta.44"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
|
||||
"@babel/helper-get-function-arity@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e"
|
||||
"@babel/helper-get-function-arity@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15"
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
|
||||
"@babel/highlight@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.40.tgz#b43d67d76bf46e1d10d227f68cddcd263786b255"
|
||||
"@babel/helper-split-export-declaration@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc"
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
|
||||
"@babel/highlight@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5"
|
||||
dependencies:
|
||||
chalk "^2.0.0"
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
"@babel/template@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8"
|
||||
"@babel/template@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f"
|
||||
dependencies:
|
||||
"@babel/code-frame" "7.0.0-beta.40"
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
babylon "7.0.0-beta.40"
|
||||
"@babel/code-frame" "7.0.0-beta.44"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
babylon "7.0.0-beta.44"
|
||||
lodash "^4.2.0"
|
||||
|
||||
"@babel/traverse@^7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e"
|
||||
"@babel/traverse@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966"
|
||||
dependencies:
|
||||
"@babel/code-frame" "7.0.0-beta.40"
|
||||
"@babel/generator" "7.0.0-beta.40"
|
||||
"@babel/helper-function-name" "7.0.0-beta.40"
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
babylon "7.0.0-beta.40"
|
||||
debug "^3.0.1"
|
||||
"@babel/code-frame" "7.0.0-beta.44"
|
||||
"@babel/generator" "7.0.0-beta.44"
|
||||
"@babel/helper-function-name" "7.0.0-beta.44"
|
||||
"@babel/helper-split-export-declaration" "7.0.0-beta.44"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
babylon "7.0.0-beta.44"
|
||||
debug "^3.1.0"
|
||||
globals "^11.1.0"
|
||||
invariant "^2.2.0"
|
||||
lodash "^4.2.0"
|
||||
|
||||
"@babel/types@7.0.0-beta.40", "@babel/types@^7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14"
|
||||
"@babel/types@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757"
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.2.0"
|
||||
|
|
@ -376,8 +383,8 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
|
|||
js-tokens "^3.0.2"
|
||||
|
||||
babel-core@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
|
||||
version "6.26.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
|
||||
dependencies:
|
||||
babel-code-frame "^6.26.0"
|
||||
babel-generator "^6.26.0"
|
||||
|
|
@ -389,24 +396,24 @@ babel-core@^6.26.0:
|
|||
babel-traverse "^6.26.0"
|
||||
babel-types "^6.26.0"
|
||||
babylon "^6.18.0"
|
||||
convert-source-map "^1.5.0"
|
||||
debug "^2.6.8"
|
||||
convert-source-map "^1.5.1"
|
||||
debug "^2.6.9"
|
||||
json5 "^0.5.1"
|
||||
lodash "^4.17.4"
|
||||
minimatch "^3.0.4"
|
||||
path-is-absolute "^1.0.1"
|
||||
private "^0.1.7"
|
||||
private "^0.1.8"
|
||||
slash "^1.0.0"
|
||||
source-map "^0.5.6"
|
||||
source-map "^0.5.7"
|
||||
|
||||
babel-eslint@^8.2.1:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.2.tgz#1102273354c6f0b29b4ea28a65f97d122296b68b"
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf"
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0-beta.40"
|
||||
"@babel/traverse" "^7.0.0-beta.40"
|
||||
"@babel/types" "^7.0.0-beta.40"
|
||||
babylon "^7.0.0-beta.40"
|
||||
"@babel/code-frame" "7.0.0-beta.44"
|
||||
"@babel/traverse" "7.0.0-beta.44"
|
||||
"@babel/types" "7.0.0-beta.44"
|
||||
babylon "7.0.0-beta.44"
|
||||
eslint-scope "~3.7.1"
|
||||
eslint-visitor-keys "^1.0.0"
|
||||
|
||||
|
|
@ -550,8 +557,8 @@ babel-helpers@^6.24.1:
|
|||
babel-template "^6.24.1"
|
||||
|
||||
babel-loader@^7.1.2:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.3.tgz#ff5b440da716e9153abb946251a9ab7670037b16"
|
||||
version "7.1.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015"
|
||||
dependencies:
|
||||
find-cache-dir "^1.0.0"
|
||||
loader-utils "^1.0.2"
|
||||
|
|
@ -1081,9 +1088,9 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
|
|||
lodash "^4.17.4"
|
||||
to-fast-properties "^1.0.3"
|
||||
|
||||
babylon@7.0.0-beta.40, babylon@^7.0.0-beta.40:
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a"
|
||||
babylon@7.0.0-beta.44:
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d"
|
||||
|
||||
babylon@^6.18.0:
|
||||
version "6.18.0"
|
||||
|
|
@ -1413,7 +1420,15 @@ chalk@^1.1.3:
|
|||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.1:
|
||||
chalk@^2.0.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^2.1.0, chalk@^2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65"
|
||||
dependencies:
|
||||
|
|
@ -1646,7 +1661,7 @@ content-type@~1.0.4:
|
|||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
|
||||
convert-source-map@^1.5.0:
|
||||
convert-source-map@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
|
||||
|
||||
|
|
@ -1671,8 +1686,8 @@ core-js@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||
|
||||
core-js@^2.4.0, core-js@^2.5.0:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
|
|
@ -1914,7 +1929,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.0.1, debug@^3.1.0:
|
||||
debug@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
dependencies:
|
||||
|
|
@ -2233,7 +2248,7 @@ es6-weak-map@^2.0.1:
|
|||
es6-iterator "^2.0.1"
|
||||
es6-symbol "^3.1.1"
|
||||
|
||||
escape-html@~1.0.3:
|
||||
escape-html@^1.0.3, escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
|
||||
|
|
@ -2916,10 +2931,14 @@ global@~4.3.0:
|
|||
min-document "^2.19.0"
|
||||
process "~0.5.1"
|
||||
|
||||
globals@^11.0.1, globals@^11.1.0:
|
||||
globals@^11.0.1:
|
||||
version "11.3.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0"
|
||||
|
||||
globals@^11.1.0:
|
||||
version "11.5.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642"
|
||||
|
||||
globals@^9.18.0:
|
||||
version "9.18.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
|
||||
|
|
@ -3176,10 +3195,16 @@ hyphenate-style-name@^1.0.2:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
|
||||
|
||||
iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13:
|
||||
iconv-lite@0.4.19, iconv-lite@^0.4.17:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||
|
||||
iconv-lite@~0.4.13:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
icss-replace-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
|
||||
|
|
@ -3272,8 +3297,8 @@ interpret@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
|
||||
|
||||
invariant@^2.2.0, invariant@^2.2.2:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688"
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
|
|
@ -3863,10 +3888,14 @@ lodash.uniq@^4.5.0:
|
|||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
||||
lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4:
|
||||
lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.3.0, lodash@~4.17.4:
|
||||
version "4.17.5"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
|
||||
|
||||
lodash@^4.17.4, lodash@^4.2.0:
|
||||
version "4.17.10"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||
|
||||
loglevel@^1.4.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
|
||||
|
|
@ -3904,8 +3933,8 @@ macaddress@^0.2.8:
|
|||
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
|
|
@ -4895,7 +4924,7 @@ preserve@^0.2.0:
|
|||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
private@^0.1.6, private@^0.1.7:
|
||||
private@^0.1.6, private@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
|
||||
|
||||
|
|
@ -5061,8 +5090,8 @@ rc@^1.1.7:
|
|||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-dom@^16.2.0:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044"
|
||||
version "16.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
loose-envify "^1.1.0"
|
||||
|
|
@ -5138,8 +5167,8 @@ react-transition-group@^2.2.1:
|
|||
warning "^3.0.0"
|
||||
|
||||
react@^16.2.0:
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"
|
||||
version "16.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
loose-envify "^1.1.0"
|
||||
|
|
@ -5471,6 +5500,10 @@ safe-regex@^1.1.0:
|
|||
dependencies:
|
||||
ret "~0.1.10"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
|
||||
sax@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
|
|
@ -5914,12 +5947,18 @@ supports-color@^4.2.1:
|
|||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0:
|
||||
supports-color@^5.1.0, supports-color@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.4.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
svgo@^0.7.0:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
|
||||
|
|
@ -6108,8 +6147,8 @@ typedarray@^0.0.6:
|
|||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
ua-parser-js@^0.7.9:
|
||||
version "0.7.17"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac"
|
||||
version "0.7.18"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
|
||||
|
||||
uglify-js@^2.8.29:
|
||||
version "2.8.29"
|
||||
|
|
@ -6395,8 +6434,8 @@ websocket-extensions@>=0.1.1:
|
|||
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
|
||||
|
||||
whatwg-fetch@>=0.10.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
|
||||
|
||||
whet.extend@~0.9.9:
|
||||
version "0.9.9"
|
||||
|
|
|
|||
|
|
@ -32,12 +32,15 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"io"
|
||||
|
||||
"github.com/elastic/gosigar"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/mohae/deepcopy"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
|
|
@ -60,10 +63,11 @@ type Dashboard struct {
|
|||
|
||||
listener net.Listener
|
||||
conns map[uint32]*client // Currently live websocket connections
|
||||
charts *SystemMessage
|
||||
commit string
|
||||
history *Message
|
||||
lock sync.RWMutex // Lock protecting the dashboard's internals
|
||||
|
||||
logdir string
|
||||
|
||||
quit chan chan error // Channel used for graceful exit
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
|
@ -71,18 +75,27 @@ type Dashboard struct {
|
|||
// client represents active websocket connection with a remote browser.
|
||||
type client struct {
|
||||
conn *websocket.Conn // Particular live websocket connection
|
||||
msg chan Message // Message queue for the update messages
|
||||
msg chan *Message // Message queue for the update messages
|
||||
logger log.Logger // Logger for the particular live websocket connection
|
||||
}
|
||||
|
||||
// New creates a new dashboard instance with the given configuration.
|
||||
func New(config *Config, commit string) (*Dashboard, error) {
|
||||
func New(config *Config, commit string, logdir string) *Dashboard {
|
||||
now := time.Now()
|
||||
db := &Dashboard{
|
||||
versionMeta := ""
|
||||
if len(params.VersionMeta) > 0 {
|
||||
versionMeta = fmt.Sprintf(" (%s)", params.VersionMeta)
|
||||
}
|
||||
return &Dashboard{
|
||||
conns: make(map[uint32]*client),
|
||||
config: config,
|
||||
quit: make(chan chan error),
|
||||
charts: &SystemMessage{
|
||||
history: &Message{
|
||||
General: &GeneralMessage{
|
||||
Commit: commit,
|
||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||
},
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
||||
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
||||
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
||||
|
|
@ -92,9 +105,9 @@ func New(config *Config, commit string) (*Dashboard, error) {
|
|||
DiskRead: emptyChartEntries(now, diskReadSampleLimit, config.Refresh),
|
||||
DiskWrite: emptyChartEntries(now, diskWriteSampleLimit, config.Refresh),
|
||||
},
|
||||
commit: commit,
|
||||
},
|
||||
logdir: logdir,
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// emptyChartEntries returns a ChartEntry array containing limit number of empty samples.
|
||||
|
|
@ -108,19 +121,20 @@ func emptyChartEntries(t time.Time, limit int, refresh time.Duration) ChartEntri
|
|||
return ce
|
||||
}
|
||||
|
||||
// Protocols is a meaningless implementation of node.Service.
|
||||
// Protocols implements the node.Service interface.
|
||||
func (db *Dashboard) Protocols() []p2p.Protocol { return nil }
|
||||
|
||||
// APIs is a meaningless implementation of node.Service.
|
||||
// APIs implements the node.Service interface.
|
||||
func (db *Dashboard) APIs() []rpc.API { return nil }
|
||||
|
||||
// Start implements node.Service, starting the data collection thread and the listening server of the dashboard.
|
||||
// Start starts the data collection thread and the listening server of the dashboard.
|
||||
// Implements the node.Service interface.
|
||||
func (db *Dashboard) Start(server *p2p.Server) error {
|
||||
log.Info("Starting dashboard")
|
||||
|
||||
db.wg.Add(2)
|
||||
go db.collectData()
|
||||
go db.collectLogs() // In case of removing this line change 2 back to 1 in wg.Add.
|
||||
go db.streamLogs()
|
||||
|
||||
http.HandleFunc("/", db.webHandler)
|
||||
http.Handle("/api", websocket.Handler(db.apiHandler))
|
||||
|
|
@ -136,7 +150,8 @@ func (db *Dashboard) Start(server *p2p.Server) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Stop implements node.Service, stopping the data collection thread and the connection listener of the dashboard.
|
||||
// Stop stops the data collection thread and the connection listener of the dashboard.
|
||||
// Implements the node.Service interface.
|
||||
func (db *Dashboard) Stop() error {
|
||||
// Close the connection listener.
|
||||
var errs []error
|
||||
|
|
@ -194,7 +209,7 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
|||
id := atomic.AddUint32(&nextID, 1)
|
||||
client := &client{
|
||||
conn: conn,
|
||||
msg: make(chan Message, 128),
|
||||
msg: make(chan *Message, 128),
|
||||
logger: log.New("id", id),
|
||||
}
|
||||
done := make(chan struct{})
|
||||
|
|
@ -218,29 +233,10 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
|||
}
|
||||
}()
|
||||
|
||||
versionMeta := ""
|
||||
if len(params.VersionMeta) > 0 {
|
||||
versionMeta = fmt.Sprintf(" (%s)", params.VersionMeta)
|
||||
}
|
||||
// Send the past data.
|
||||
client.msg <- Message{
|
||||
General: &GeneralMessage{
|
||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||
Commit: db.commit,
|
||||
},
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: db.charts.ActiveMemory,
|
||||
VirtualMemory: db.charts.VirtualMemory,
|
||||
NetworkIngress: db.charts.NetworkIngress,
|
||||
NetworkEgress: db.charts.NetworkEgress,
|
||||
ProcessCPU: db.charts.ProcessCPU,
|
||||
SystemCPU: db.charts.SystemCPU,
|
||||
DiskRead: db.charts.DiskRead,
|
||||
DiskWrite: db.charts.DiskWrite,
|
||||
},
|
||||
}
|
||||
// Start tracking the connection and drop at connection loss.
|
||||
db.lock.Lock()
|
||||
// Send the past data.
|
||||
client.msg <- deepcopy.Copy(db.history).(*Message)
|
||||
// Start tracking the connection and drop at connection loss.
|
||||
db.conns[id] = client
|
||||
db.lock.Unlock()
|
||||
defer func() {
|
||||
|
|
@ -249,29 +245,53 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
|||
db.lock.Unlock()
|
||||
}()
|
||||
for {
|
||||
fail := []byte{}
|
||||
if _, err := conn.Read(fail); err != nil {
|
||||
r := new(Request)
|
||||
if err := websocket.JSON.Receive(conn, r); err != nil {
|
||||
if err != io.EOF {
|
||||
client.logger.Warn("Failed to receive request", "err", err)
|
||||
}
|
||||
close(done)
|
||||
return
|
||||
}
|
||||
// Ignore all messages
|
||||
if r.Logs != nil {
|
||||
db.handleLogRequest(r.Logs, client)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// meterCollector returns a function, which retrieves a specific meter.
|
||||
func meterCollector(name string) func() int64 {
|
||||
if metric := metrics.DefaultRegistry.Get(name); metric != nil {
|
||||
m := metric.(metrics.Meter)
|
||||
return func() int64 {
|
||||
return m.Count()
|
||||
}
|
||||
}
|
||||
return func() int64 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// collectData collects the required data to plot on the dashboard.
|
||||
func (db *Dashboard) collectData() {
|
||||
defer db.wg.Done()
|
||||
|
||||
systemCPUUsage := gosigar.Cpu{}
|
||||
systemCPUUsage.Get()
|
||||
var (
|
||||
mem runtime.MemStats
|
||||
|
||||
prevNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
||||
prevNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||
collectNetworkIngress = meterCollector("p2p/InboundTraffic")
|
||||
collectNetworkEgress = meterCollector("p2p/OutboundTraffic")
|
||||
collectDiskRead = meterCollector("eth/db/chaindata/disk/read")
|
||||
collectDiskWrite = meterCollector("eth/db/chaindata/disk/write")
|
||||
|
||||
prevNetworkIngress = collectNetworkIngress()
|
||||
prevNetworkEgress = collectNetworkEgress()
|
||||
prevProcessCPUTime = getProcessCPUTime()
|
||||
prevSystemCPUUsage = systemCPUUsage
|
||||
prevDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||
prevDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||
prevDiskRead = collectDiskRead()
|
||||
prevDiskWrite = collectDiskWrite()
|
||||
|
||||
frequency = float64(db.config.Refresh / time.Second)
|
||||
numCPU = float64(runtime.NumCPU())
|
||||
|
|
@ -285,12 +305,12 @@ func (db *Dashboard) collectData() {
|
|||
case <-time.After(db.config.Refresh):
|
||||
systemCPUUsage.Get()
|
||||
var (
|
||||
curNetworkIngress = metrics.DefaultRegistry.Get("p2p/InboundTraffic").(metrics.Meter).Count()
|
||||
curNetworkEgress = metrics.DefaultRegistry.Get("p2p/OutboundTraffic").(metrics.Meter).Count()
|
||||
curNetworkIngress = collectNetworkIngress()
|
||||
curNetworkEgress = collectNetworkEgress()
|
||||
curProcessCPUTime = getProcessCPUTime()
|
||||
curSystemCPUUsage = systemCPUUsage
|
||||
curDiskRead = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/read").(metrics.Meter).Count()
|
||||
curDiskWrite = metrics.DefaultRegistry.Get("eth/db/chaindata/disk/write").(metrics.Meter).Count()
|
||||
curDiskRead = collectDiskRead()
|
||||
curDiskWrite = collectDiskWrite()
|
||||
|
||||
deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
|
||||
deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
|
||||
|
|
@ -341,14 +361,17 @@ func (db *Dashboard) collectData() {
|
|||
Time: now,
|
||||
Value: float64(deltaDiskWrite) / frequency,
|
||||
}
|
||||
db.charts.ActiveMemory = append(db.charts.ActiveMemory[1:], activeMemory)
|
||||
db.charts.VirtualMemory = append(db.charts.VirtualMemory[1:], virtualMemory)
|
||||
db.charts.NetworkIngress = append(db.charts.NetworkIngress[1:], networkIngress)
|
||||
db.charts.NetworkEgress = append(db.charts.NetworkEgress[1:], networkEgress)
|
||||
db.charts.ProcessCPU = append(db.charts.ProcessCPU[1:], processCPU)
|
||||
db.charts.SystemCPU = append(db.charts.SystemCPU[1:], systemCPU)
|
||||
db.charts.DiskRead = append(db.charts.DiskRead[1:], diskRead)
|
||||
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
||||
sys := db.history.System
|
||||
db.lock.Lock()
|
||||
sys.ActiveMemory = append(sys.ActiveMemory[1:], activeMemory)
|
||||
sys.VirtualMemory = append(sys.VirtualMemory[1:], virtualMemory)
|
||||
sys.NetworkIngress = append(sys.NetworkIngress[1:], networkIngress)
|
||||
sys.NetworkEgress = append(sys.NetworkEgress[1:], networkEgress)
|
||||
sys.ProcessCPU = append(sys.ProcessCPU[1:], processCPU)
|
||||
sys.SystemCPU = append(sys.SystemCPU[1:], systemCPU)
|
||||
sys.DiskRead = append(sys.DiskRead[1:], diskRead)
|
||||
sys.DiskWrite = append(sys.DiskWrite[1:], diskWrite)
|
||||
db.lock.Unlock()
|
||||
|
||||
db.sendToAll(&Message{
|
||||
System: &SystemMessage{
|
||||
|
|
@ -366,34 +389,12 @@ func (db *Dashboard) collectData() {
|
|||
}
|
||||
}
|
||||
|
||||
// collectLogs collects and sends the logs to the active dashboards.
|
||||
func (db *Dashboard) collectLogs() {
|
||||
defer db.wg.Done()
|
||||
|
||||
id := 1
|
||||
// TODO (kurkomisi): log collection comes here.
|
||||
for {
|
||||
select {
|
||||
case errc := <-db.quit:
|
||||
errc <- nil
|
||||
return
|
||||
case <-time.After(db.config.Refresh / 2):
|
||||
db.sendToAll(&Message{
|
||||
Logs: &LogsMessage{
|
||||
Log: []string{fmt.Sprintf("%-4d: This is a fake log.", id)},
|
||||
},
|
||||
})
|
||||
id++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendToAll sends the given message to the active dashboards.
|
||||
func (db *Dashboard) sendToAll(msg *Message) {
|
||||
db.lock.Lock()
|
||||
for _, c := range db.conns {
|
||||
select {
|
||||
case c.msg <- *msg:
|
||||
case c.msg <- msg:
|
||||
default:
|
||||
c.conn.Close()
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue