Merge pull request #1 from ethereum/master

update from official
This commit is contained in:
cpusoft 2018-03-29 13:28:56 +08:00 committed by GitHub
commit e440ecef0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 443 additions and 610 deletions

View file

@ -47,14 +47,12 @@ matrix:
script: script:
- go run build/ci.go lint - go run build/ci.go lint
# This builder does the Ubuntu PPA and Linux Azure uploads # This builder does the Ubuntu PPA upload
- os: linux - os: linux
dist: trusty dist: trusty
sudo: required
go: "1.10" go: "1.10"
env: env:
- ubuntu-ppa - ubuntu-ppa
- azure-linux
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
addons: addons:
@ -63,11 +61,25 @@ matrix:
- devscripts - devscripts
- debhelper - debhelper
- dput - dput
- gcc-multilib
- fakeroot - fakeroot
script: script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum - go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
# This builder does the Linux Azure uploads
- os: linux
dist: trusty
sudo: required
go: "1.10"
env:
- azure-linux
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- gcc-multilib
script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go install - go run build/ci.go install
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch 386 - go run build/ci.go install -arch 386
@ -181,7 +193,6 @@ matrix:
# This builder does the Azure archive purges to avoid accumulating junk # This builder does the Azure archive purges to avoid accumulating junk
- os: linux - os: linux
dist: trusty dist: trusty
sudo: required
go: "1.10" go: "1.10"
env: env:
- azure-purge - azure-purge

View file

@ -1 +1 @@
1.8.3 1.8.4

View file

@ -95,6 +95,34 @@ Requires a first argument of the file to write to.
Optional second and third arguments control the first and Optional second and third arguments control the first and
last block to write. In this mode, the file will be appended last block to write. In this mode, the file will be appended
if already existing.`, if already existing.`,
}
importPreimagesCommand = cli.Command{
Action: utils.MigrateFlags(importPreimages),
Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
The import-preimages command imports hash preimages from an RLP encoded stream.`,
}
exportPreimagesCommand = cli.Command{
Action: utils.MigrateFlags(exportPreimages),
Name: "export-preimages",
Usage: "Export the preimage database into an RLP stream",
ArgsUsage: "<dumpfile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
The export-preimages command export hash preimages to an RLP encoded stream`,
} }
copydbCommand = cli.Command{ copydbCommand = cli.Command{
Action: utils.MigrateFlags(copyDb), Action: utils.MigrateFlags(copyDb),
@ -299,7 +327,39 @@ func exportChain(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf("Export error: %v\n", err) utils.Fatalf("Export error: %v\n", err)
} }
fmt.Printf("Export done in %v", time.Since(start)) fmt.Printf("Export done in %v\n", time.Since(start))
return nil
}
// importPreimages imports preimage data from the specified file.
func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
start := time.Now()
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
return nil
}
// exportPreimages dumps the preimage data to specified json file in streaming way.
func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
stack := makeFullNode(ctx)
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
start := time.Now()
if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
return nil return nil
} }

View file

@ -32,7 +32,7 @@ import (
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
"github.com/naoina/toml" "github.com/naoina/toml"
) )

View file

@ -155,6 +155,8 @@ func init() {
initCommand, initCommand,
importCommand, importCommand,
exportCommand, exportCommand,
importPreimagesCommand,
exportPreimagesCommand,
copydbCommand, copydbCommand,
removedbCommand, removedbCommand,
dumpCommand, dumpCommand,

View file

@ -20,6 +20,7 @@ package main
import ( import (
"math/rand" "math/rand"
"os" "os"
"strings"
"time" "time"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -34,7 +35,7 @@ func main() {
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "network", Name: "network",
Usage: "name of the network to administer", Usage: "name of the network to administer (no spaces or hyphens, please)",
}, },
cli.IntFlag{ cli.IntFlag{
Name: "loglevel", Name: "loglevel",
@ -47,6 +48,10 @@ func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
network := c.String("network")
if strings.Contains(network, " ") || strings.Contains(network, "-") {
log.Crit("No spaces or hyphens allowed in network name")
}
// Start the wizard and relinquish control // Start the wizard and relinquish control
makeWizard(c.String("network")).run() makeWizard(c.String("network")).run()
return nil return nil

View file

@ -27,8 +27,11 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
@ -105,6 +108,8 @@ func ImportChain(chain *core.BlockChain, fn string) error {
} }
log.Info("Importing blockchain", "file", fn) log.Info("Importing blockchain", "file", fn)
// Open the file handle and potentially unwrap the gzip stream
fh, err := os.Open(fn) fh, err := os.Open(fn)
if err != nil { if err != nil {
return err return err
@ -180,8 +185,12 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
return nil return nil
} }
// ExportChain exports a blockchain into the specified file, truncating any data
// already present in the file.
func ExportChain(blockchain *core.BlockChain, fn string) error { func ExportChain(blockchain *core.BlockChain, fn string) error {
log.Info("Exporting blockchain", "file", fn) log.Info("Exporting blockchain", "file", fn)
// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
return err return err
@ -193,7 +202,7 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
writer = gzip.NewWriter(writer) writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close() defer writer.(*gzip.Writer).Close()
} }
// Iterate over the blocks and export them
if err := blockchain.Export(writer); err != nil { if err := blockchain.Export(writer); err != nil {
return err return err
} }
@ -202,9 +211,12 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
return nil return nil
} }
// ExportAppendChain exports a blockchain into the specified file, appending to
// the file if data already exists in it.
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error { func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
log.Info("Exporting blockchain", "file", fn) log.Info("Exporting blockchain", "file", fn)
// TODO verify mode perms
// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
if err != nil { if err != nil {
return err return err
@ -216,10 +228,86 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
writer = gzip.NewWriter(writer) writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close() defer writer.(*gzip.Writer).Close()
} }
// Iterate over the blocks and export them
if err := blockchain.ExportN(writer, first, last); err != nil { if err := blockchain.ExportN(writer, first, last); err != nil {
return err return err
} }
log.Info("Exported blockchain to", "file", fn) log.Info("Exported blockchain to", "file", fn)
return nil return nil
} }
// ImportPreimages imports a batch of exported hash preimages into the database.
func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
log.Info("Importing preimages", "file", fn)
// Open the file handle and potentially unwrap the gzip stream
fh, err := os.Open(fn)
if err != nil {
return err
}
defer fh.Close()
var reader io.Reader = fh
if strings.HasSuffix(fn, ".gz") {
if reader, err = gzip.NewReader(reader); err != nil {
return err
}
}
stream := rlp.NewStream(reader, 0)
// Import the preimages in batches to prevent disk trashing
preimages := make(map[common.Hash][]byte)
for {
// Read the next entry and ensure it's not junk
var blob []byte
if err := stream.Decode(&blob); err != nil {
if err == io.EOF {
break
}
return err
}
// Accumulate the preimages and flush when enough ws gathered
preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
if len(preimages) > 1024 {
if err := core.WritePreimages(db, 0, preimages); err != nil {
return err
}
preimages = make(map[common.Hash][]byte)
}
}
// Flush the last batch preimage data
if len(preimages) > 0 {
return core.WritePreimages(db, 0, preimages)
}
return nil
}
// ExportPreimages exports all known hash preimages into the specified file,
// truncating any data already present in the file.
func ExportPreimages(db *ethdb.LDBDatabase, fn string) error {
log.Info("Exporting preimages", "file", fn)
// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()
var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
// Iterate over the preimages and export them
it := db.NewIteratorWithPrefix([]byte("secure-key-"))
for it.Next() {
if err := rlp.Encode(writer, it.Value()); err != nil {
return err
}
}
log.Info("Exported preimages", "file", fn)
return nil
}

View file

@ -55,7 +55,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )

View file

@ -114,7 +114,7 @@ func (c *Compiler) Compile() (string, []error) {
} }
// next returns the next token and increments the // next returns the next token and increments the
// posititon. // position.
func (c *Compiler) next() token { func (c *Compiler) next() token {
token := c.tokens[c.pos] token := c.tokens[c.pos]
c.pos++ c.pos++

View file

@ -60,13 +60,26 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
// GetHashFn returns a GetHashFunc which retrieves header hashes by number // GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
return func(n uint64) common.Hash { var cache map[uint64]common.Hash
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
if header.Number.Uint64() == n {
return header.Hash()
}
}
return func(n uint64) common.Hash {
// If there's no hash cache yet, make one
if cache == nil {
cache = map[uint64]common.Hash{
ref.Number.Uint64() - 1: ref.ParentHash,
}
}
// Try to fulfill the request from the cache
if hash, ok := cache[n]; ok {
return hash
}
// Not cached, iterate the blocks and cache the hashes
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
cache[header.Number.Uint64()-1] = header.ParentHash
if n == header.Number.Uint64()-1 {
return header.ParentHash
}
}
return common.Hash{} return common.Hash{}
} }
} }

View file

@ -23,6 +23,7 @@ import (
"math" "math"
"math/big" "math/big"
mrand "math/rand" mrand "math/rand"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -32,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
"sync/atomic"
) )
const ( const (

View file

@ -83,7 +83,7 @@ type StateDB struct {
lock sync.Mutex lock sync.Mutex
} }
// Create a new state from a given trie // Create a new state from a given trie.
func New(root common.Hash, db Database) (*StateDB, error) { func New(root common.Hash, db Database) (*StateDB, error) {
tr, err := db.OpenTrie(root) tr, err := db.OpenTrie(root)
if err != nil { if err != nil {
@ -110,7 +110,7 @@ func (self *StateDB) Error() error {
return self.dbErr return self.dbErr
} }
// Reset clears out all emphemeral state objects from the state db, but keeps // Reset clears out all ephemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations. // the underlying state trie to avoid reloading data for the next operations.
func (self *StateDB) Reset(root common.Hash) error { func (self *StateDB) Reset(root common.Hash) error {
tr, err := self.db.OpenTrie(root) tr, err := self.db.OpenTrie(root)
@ -235,10 +235,10 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
return common.BytesToHash(stateObject.CodeHash()) return common.BytesToHash(stateObject.CodeHash())
} }
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { func (self *StateDB) GetState(addr common.Address, bhash common.Hash) common.Hash {
stateObject := self.getStateObject(a) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.GetState(self.db, b) return stateObject.GetState(self.db, bhash)
} }
return common.Hash{} return common.Hash{}
} }
@ -250,8 +250,8 @@ func (self *StateDB) Database() Database {
// StorageTrie returns the storage trie of an account. // StorageTrie returns the storage trie of an account.
// The return value is a copy and is nil for non-existent accounts. // The return value is a copy and is nil for non-existent accounts.
func (self *StateDB) StorageTrie(a common.Address) Trie { func (self *StateDB) StorageTrie(addr common.Address) Trie {
stateObject := self.getStateObject(a) stateObject := self.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return nil return nil
} }
@ -271,7 +271,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
* SETTERS * SETTERS
*/ */
// AddBalance adds amount to the account associated with addr // AddBalance adds amount to the account associated with addr.
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
@ -279,7 +279,7 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
} }
} }
// SubBalance subtracts amount from the account associated with addr // SubBalance subtracts amount from the account associated with addr.
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) { func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
@ -308,7 +308,7 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) {
} }
} }
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) { func (self *StateDB) SetState(addr common.Address, key, value common.Hash) {
stateObject := self.GetOrNewStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetState(self.db, key, value) stateObject.SetState(self.db, key, value)
@ -337,7 +337,7 @@ func (self *StateDB) Suicide(addr common.Address) bool {
} }
// //
// Setting, updating & deleting state object methods // Setting, updating & deleting state object methods.
// //
// updateStateObject writes the given object to the trie. // updateStateObject writes the given object to the trie.
@ -388,7 +388,7 @@ func (self *StateDB) setStateObject(object *stateObject) {
self.stateObjects[object.Address()] = object self.stateObjects[object.Address()] = object
} }
// Retrieve a state object or create a new state object if nil // Retrieve a state object or create a new state object if nil.
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
stateObject := self.getStateObject(addr) stateObject := self.getStateObject(addr)
if stateObject == nil || stateObject.deleted { if stateObject == nil || stateObject.deleted {

View file

@ -17,19 +17,8 @@
/* /*
Package vm implements the Ethereum Virtual Machine. Package vm implements the Ethereum Virtual Machine.
The vm package implements two EVMs, a byte code VM and a JIT VM. The BC The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops
(Byte Code) VM loops over a set of bytes and executes them according to the set over a set of bytes and executes them according to the set of rules defined
of rules defined in the Ethereum yellow paper. When the BC VM is invoked it in the Ethereum yellow paper.
invokes the JIT VM in a separate goroutine and compiles the byte code in JIT
instructions.
The JIT VM, when invoked, loops around a set of pre-defined instructions until
it either runs of gas, causes an internal error, returns or stops.
The JIT optimiser attempts to pre-compile instructions in to chunks or segments
such as multiple PUSH operations and static JUMPs. It does this by analysing the
opcodes and attempts to match certain regions to known sets. Whenever the
optimiser finds said segments it creates a new instruction and replaces the
first occurrence in the sequence.
*/ */
package vm package vm

View file

@ -111,7 +111,7 @@ type EVM struct {
callGasTemp uint64 callGasTemp uint64
} }
// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should // NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*. // only ever be used *once*.
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
evm := &EVM{ evm := &EVM{
@ -221,7 +221,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
to = AccountRef(caller.Address()) to = AccountRef(caller.Address())
) )
// initialise a new contract and set the code that is to be used by the // initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context // EVM. The contract is a scoped environment for this execution context
// only. // only.
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
@ -341,7 +341,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value) evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
// initialise a new contract and set the code that is to be used by the // initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context // EVM. The contract is a scoped environment for this execution context
// only. // only.
contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract := NewContract(caller, AccountRef(contractAddr), value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)

View file

@ -39,20 +39,18 @@ var (
) )
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
stack.push(math.U256(x.Add(x, y))) math.U256(y.Add(x, y))
evm.interpreter.intPool.put(y)
evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
stack.push(math.U256(x.Sub(x, y))) math.U256(y.Sub(x, y))
evm.interpreter.intPool.put(y)
evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
@ -66,44 +64,39 @@ func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
} }
func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
if y.Sign() != 0 { if y.Sign() != 0 {
stack.push(math.U256(x.Div(x, y))) math.U256(y.Div(x, y))
} else { } else {
stack.push(new(big.Int)) y.SetUint64(0)
} }
evm.interpreter.intPool.put(x)
evm.interpreter.intPool.put(y)
return nil, nil return nil, nil
} }
func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := math.S256(stack.pop()), math.S256(stack.pop())
if y.Sign() == 0 { res := evm.interpreter.intPool.getZero()
stack.push(new(big.Int))
return nil, nil if y.Sign() == 0 || x.Sign() == 0 {
stack.push(res)
} else { } else {
n := new(big.Int) if x.Sign() != y.Sign() {
if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 { res.Div(x.Abs(x), y.Abs(y))
n.SetInt64(-1) res.Neg(res)
} else { } else {
n.SetInt64(1) res.Div(x.Abs(x), y.Abs(y))
} }
res := x.Div(x.Abs(x), y.Abs(y))
res.Mul(res, n)
stack.push(math.U256(res)) stack.push(math.U256(res))
} }
evm.interpreter.intPool.put(y) evm.interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.pop()
if y.Sign() == 0 { if y.Sign() == 0 {
stack.push(new(big.Int)) stack.push(x.SetUint64(0))
} else { } else {
stack.push(math.U256(x.Mod(x, y))) stack.push(math.U256(x.Mod(x, y)))
} }
@ -113,23 +106,20 @@ func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop()) x, y := math.S256(stack.pop()), math.S256(stack.pop())
res := evm.interpreter.intPool.getZero()
if y.Sign() == 0 { if y.Sign() == 0 {
stack.push(new(big.Int)) stack.push(res)
} else { } else {
n := new(big.Int)
if x.Sign() < 0 { if x.Sign() < 0 {
n.SetInt64(-1) res.Mod(x.Abs(x), y.Abs(y))
res.Neg(res)
} else { } else {
n.SetInt64(1) res.Mod(x.Abs(x), y.Abs(y))
} }
res := x.Mod(x.Abs(x), y.Abs(y))
res.Mul(res, n)
stack.push(math.U256(res)) stack.push(math.U256(res))
} }
evm.interpreter.intPool.put(y) evm.interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
@ -163,32 +153,30 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
} }
func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.pop() x := stack.peek()
stack.push(math.U256(x.Not(x))) math.U256(x.Not(x))
return nil, nil return nil, nil
} }
func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
if x.Cmp(y) < 0 { if x.Cmp(y) < 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1)) y.SetUint64(1)
} else { } else {
stack.push(new(big.Int)) y.SetUint64(0)
} }
evm.interpreter.intPool.put(x)
evm.interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
if x.Cmp(y) > 0 { if x.Cmp(y) > 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1)) y.SetUint64(1)
} else { } else {
stack.push(new(big.Int)) y.SetUint64(0)
} }
evm.interpreter.intPool.put(x)
evm.interpreter.intPool.put(x, y)
return nil, nil return nil, nil
} }
@ -270,18 +258,18 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
} }
func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
stack.push(x.Or(x, y)) y.Or(x, y)
evm.interpreter.intPool.put(y) evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.peek()
stack.push(x.Xor(x, y)) y.Xor(x, y)
evm.interpreter.intPool.put(y) evm.interpreter.intPool.put(x)
return nil, nil return nil, nil
} }
@ -300,13 +288,12 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop() x, y, z := stack.pop(), stack.pop(), stack.pop()
if z.Cmp(bigZero) > 0 { if z.Cmp(bigZero) > 0 {
add := x.Add(x, y) x.Add(x, y)
add.Mod(add, z) x.Mod(x, z)
stack.push(math.U256(add)) stack.push(math.U256(x))
} else { } else {
stack.push(new(big.Int)) stack.push(x.SetUint64(0))
} }
evm.interpreter.intPool.put(y, z) evm.interpreter.intPool.put(y, z)
return nil, nil return nil, nil
} }
@ -314,13 +301,12 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y, z := stack.pop(), stack.pop(), stack.pop() x, y, z := stack.pop(), stack.pop(), stack.pop()
if z.Cmp(bigZero) > 0 { if z.Cmp(bigZero) > 0 {
mul := x.Mul(x, y) x.Mul(x, y)
mul.Mod(mul, z) x.Mod(x, z)
stack.push(math.U256(mul)) stack.push(math.U256(x))
} else { } else {
stack.push(new(big.Int)) stack.push(x.SetUint64(0))
} }
evm.interpreter.intPool.put(y, z) evm.interpreter.intPool.put(y, z)
return nil, nil return nil, nil
} }
@ -393,8 +379,7 @@ func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
if evm.vmConfig.EnablePreimageRecording { if evm.vmConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(common.BytesToHash(hash), data) evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
} }
stack.push(evm.interpreter.intPool.get().SetBytes(hash))
stack.push(new(big.Int).SetBytes(hash))
evm.interpreter.intPool.put(offset, size) evm.interpreter.intPool.put(offset, size)
return nil, nil return nil, nil
@ -406,10 +391,8 @@ func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
} }
func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
addr := common.BigToAddress(stack.pop()) slot := stack.peek()
balance := evm.StateDB.GetBalance(addr) slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot)))
stack.push(new(big.Int).Set(balance))
return nil, nil return nil, nil
} }
@ -429,7 +412,7 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
} }
func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32))) stack.push(evm.interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
return nil, nil return nil, nil
} }
@ -460,10 +443,11 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
memOffset = stack.pop() memOffset = stack.pop()
dataOffset = stack.pop() dataOffset = stack.pop()
length = stack.pop() length = stack.pop()
)
defer evm.interpreter.intPool.put(memOffset, dataOffset, length)
end := new(big.Int).Add(dataOffset, length) end = evm.interpreter.intPool.get().Add(dataOffset, length)
)
defer evm.interpreter.intPool.put(memOffset, dataOffset, length, end)
if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() { if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
return nil, errReturnDataOutOfBounds return nil, errReturnDataOutOfBounds
} }
@ -473,11 +457,8 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
} }
func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
a := stack.pop() slot := stack.peek()
slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
addr := common.BigToAddress(a)
a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
stack.push(a)
return nil, nil return nil, nil
} }
@ -485,6 +466,7 @@ func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code))) l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
stack.push(l) stack.push(l)
return nil, nil return nil, nil
} }
@ -527,9 +509,8 @@ func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 { if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
stack.push(evm.GetHash(num.Uint64()).Big()) stack.push(evm.GetHash(num.Uint64()).Big())
} else { } else {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} }
evm.interpreter.intPool.put(num, n) evm.interpreter.intPool.put(num, n)
return nil, nil return nil, nil
} }
@ -540,22 +521,22 @@ func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
} }
func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(new(big.Int).Set(evm.Time))) stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Time)))
return nil, nil return nil, nil
} }
func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(new(big.Int).Set(evm.BlockNumber))) stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.BlockNumber)))
return nil, nil return nil, nil
} }
func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(new(big.Int).Set(evm.Difficulty))) stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Difficulty)))
return nil, nil return nil, nil
} }
func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit))) stack.push(math.U256(evm.interpreter.intPool.get().SetUint64(evm.GasLimit)))
return nil, nil return nil, nil
} }
@ -566,7 +547,7 @@ func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
offset := stack.pop() offset := stack.pop()
val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32)) val := evm.interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
stack.push(val) stack.push(val)
evm.interpreter.intPool.put(offset) evm.interpreter.intPool.put(offset)
@ -670,9 +651,9 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
// rule) and treat as an error, if the ruleset is frontier we must // rule) and treat as an error, if the ruleset is frontier we must
// ignore this error and pretend the operation was successful. // ignore this error and pretend the operation was successful.
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas { } else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else { } else {
stack.push(addr.Big()) stack.push(addr.Big())
} }
@ -701,9 +682,9 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
} }
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value) ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
if err != nil { if err != nil {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else { } else {
stack.push(big.NewInt(1)) stack.push(evm.interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@ -730,9 +711,9 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
} }
ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value) ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
if err != nil { if err != nil {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else { } else {
stack.push(big.NewInt(1)) stack.push(evm.interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@ -755,9 +736,9 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas) ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
if err != nil { if err != nil {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else { } else {
stack.push(big.NewInt(1)) stack.push(evm.interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@ -780,9 +761,9 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas) ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
if err != nil { if err != nil {
stack.push(new(big.Int)) stack.push(evm.interpreter.intPool.getZero())
} else { } else {
stack.push(big.NewInt(1)) stack.push(evm.interpreter.intPool.get().SetUint64(1))
} }
if err == nil || err == errExecutionReverted { if err == nil || err == errExecutionReverted {
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)

View file

@ -32,7 +32,7 @@ type twoOperandTest struct {
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, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -68,7 +68,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
func TestByteOp(t *testing.T) { func TestByteOp(t *testing.T) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
) )
tests := []struct { tests := []struct {
@ -198,7 +198,7 @@ func TestSLT(t *testing.T) {
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, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
) )
// convert args // convert args

View file

@ -28,10 +28,6 @@ import (
type Config struct { type Config struct {
// Debug enabled debugging Interpreter options // Debug enabled debugging Interpreter options
Debug bool Debug bool
// EnableJit enabled the JIT VM
EnableJit bool
// ForceJit forces the JIT VM
ForceJit bool
// Tracer is the op code logger // Tracer is the op code logger
Tracer Tracer Tracer Tracer
// NoRecursion disabled Interpreter call, callcode, // NoRecursion disabled Interpreter call, callcode,
@ -46,8 +42,8 @@ type Config struct {
} }
// Interpreter is used to run Ethereum based contracts and will utilise the // Interpreter is used to run Ethereum based contracts and will utilise the
// passed evmironment to query external sources for state information. // passed environment to query external sources for state information.
// The Interpreter will run the byte code VM or JIT VM based on the passed // The Interpreter will run the byte code VM based on the passed
// configuration. // configuration.
type Interpreter struct { type Interpreter struct {
evm *EVM evm *EVM
@ -188,7 +184,7 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
} }
} }
// consume the gas and return an error if not enough gas is available. // consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method cas get the proper cost // cost is explicitly set so that the capture state defer method can get the proper cost
cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
if err != nil || !contract.UseGas(cost) { if err != nil || !contract.UseGas(cost) {
return nil, ErrOutOfGas return nil, ErrOutOfGas

View file

@ -32,24 +32,36 @@ func newIntPool() *intPool {
return &intPool{pool: newstack()} return &intPool{pool: newstack()}
} }
// get retrieves a big int from the pool, allocating one if the pool is empty.
// Note, the returned int's value is arbitrary and will not be zeroed!
func (p *intPool) get() *big.Int { func (p *intPool) get() *big.Int {
if p.pool.len() > 0 { if p.pool.len() > 0 {
return p.pool.pop() return p.pool.pop()
} }
return new(big.Int) return new(big.Int)
} }
// getZero retrieves a big int from the pool, setting it to zero or allocating
// a new one if the pool is empty.
func (p *intPool) getZero() *big.Int {
if p.pool.len() > 0 {
return p.pool.pop().SetUint64(0)
}
return new(big.Int)
}
// put returns an allocated big int to the pool to be later reused by get calls.
// Note, the values as saved as is; neither put nor get zeroes the ints out!
func (p *intPool) put(is ...*big.Int) { func (p *intPool) put(is ...*big.Int) {
if len(p.pool.data) > poolLimit { if len(p.pool.data) > poolLimit {
return return
} }
for _, i := range is { for _, i := range is {
// verifyPool is a build flag. Pool verification makes sure the integrity // verifyPool is a build flag. Pool verification makes sure the integrity
// of the integer pool by comparing values to a default value. // of the integer pool by comparing values to a default value.
if verifyPool { if verifyPool {
i.Set(checkVal) i.Set(checkVal)
} }
p.pool.push(i) p.pool.push(i)
} }
} }

View file

@ -48,7 +48,7 @@ type dummyStateDB struct {
func TestStoreCapture(t *testing.T) { func TestStoreCapture(t *testing.T) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
logger = NewStructLogger(nil) logger = NewStructLogger(nil)
mem = NewMemory() mem = NewMemory()
stack = newstack() stack = newstack()

View file

@ -41,7 +41,6 @@ type Config struct {
GasLimit uint64 GasLimit uint64
GasPrice *big.Int GasPrice *big.Int
Value *big.Int Value *big.Int
DisableJit bool // "disable" so it's enabled by default
Debug bool Debug bool
EVMConfig vm.Config EVMConfig vm.Config
@ -92,8 +91,7 @@ func setDefaults(cfg *Config) {
// It returns the EVM's return value, the new state and an error if it failed. // It returns the EVM's return value, the new state and an error if it failed.
// //
// Executes sets up a in memory, temporarily, environment for the execution of // Executes sets up a in memory, temporarily, environment for the execution of
// the given code. It enabled the JIT by default and make sure that it's restored // the given code. It makes sure that it's restored to it's original state afterwards.
// to it's original state afterwards.
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
if cfg == nil { if cfg == nil {
cfg = new(Config) cfg = new(Config)

View file

@ -1,389 +0,0 @@
// 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/>.
// +build evmjit
package vm
/*
void* evmjit_create();
int evmjit_run(void* _jit, void* _data, void* _env);
void evmjit_destroy(void* _jit);
// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
// More: https://github.com/ethereum/evmjit
#cgo LDFLAGS: -levmjit
*/
import "C"
/*
import (
"bytes"
"errors"
"fmt"
"math/big"
"unsafe"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
type JitVm struct {
env EVM
me ContextRef
callerAddr []byte
price *big.Int
data RuntimeData
}
type i256 [32]byte
type RuntimeData struct {
gas int64
gasPrice int64
callData *byte
callDataSize uint64
address i256
caller i256
origin i256
callValue i256
coinBase i256
difficulty i256
gasLimit i256
number uint64
timestamp int64
code *byte
codeSize uint64
codeHash i256
}
func hash2llvm(h []byte) i256 {
var m i256
copy(m[len(m)-len(h):], h) // right aligned copy
return m
}
func llvm2hash(m *i256) []byte {
return C.GoBytes(unsafe.Pointer(m), C.int(len(m)))
}
func llvm2hashRef(m *i256) []byte {
return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)]
}
func address2llvm(addr []byte) i256 {
n := hash2llvm(addr)
bswap(&n)
return n
}
// bswap swap bytes of the 256-bit integer on LLVM side
// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
func bswap(m *i256) *i256 {
for i, l := 0, len(m); i < l/2; i++ {
m[i], m[l-i-1] = m[l-i-1], m[i]
}
return m
}
func trim(m []byte) []byte {
skip := 0
for i := 0; i < len(m); i++ {
if m[i] == 0 {
skip++
} else {
break
}
}
return m[skip:]
}
func getDataPtr(m []byte) *byte {
var p *byte
if len(m) > 0 {
p = &m[0]
}
return p
}
func big2llvm(n *big.Int) i256 {
m := hash2llvm(n.Bytes())
bswap(&m)
return m
}
func llvm2big(m *i256) *big.Int {
n := big.NewInt(0)
for i := 0; i < len(m); i++ {
b := big.NewInt(int64(m[i]))
b.Lsh(b, uint(i)*8)
n.Add(n, b)
}
return n
}
// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
// User must ensure that referenced memory is available to Go until the data is copied or not needed any more
func llvm2bytesRef(data *byte, length uint64) []byte {
if length == 0 {
return nil
}
if data == nil {
panic("Unexpected nil data pointer")
}
return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
}
func untested(condition bool, message string) {
if condition {
panic("Condition `" + message + "` tested. Remove assert.")
}
}
func assert(condition bool, message string) {
if !condition {
panic("Assert `" + message + "` failed!")
}
}
func NewJitVm(env EVM) *JitVm {
return &JitVm{env: env}
}
func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
// TODO: depth is increased but never checked by VM. VM should not know about it at all.
self.env.SetDepth(self.env.Depth() + 1)
// TODO: Move it to Env.Call() or sth
if Precompiled[string(me.Address())] != nil {
// if it's address of precompiled contract
// fallback to standard VM
stdVm := New(self.env)
return stdVm.Run(me, caller, code, value, gas, price, callData)
}
if self.me != nil {
panic("JitVm.Run() can be called only once per JitVm instance")
}
self.me = me
self.callerAddr = caller.Address()
self.price = price
self.data.gas = gas.Int64()
self.data.gasPrice = price.Int64()
self.data.callData = getDataPtr(callData)
self.data.callDataSize = uint64(len(callData))
self.data.address = address2llvm(self.me.Address())
self.data.caller = address2llvm(caller.Address())
self.data.origin = address2llvm(self.env.Origin())
self.data.callValue = big2llvm(value)
self.data.coinBase = address2llvm(self.env.Coinbase())
self.data.difficulty = big2llvm(self.env.Difficulty())
self.data.gasLimit = big2llvm(self.env.GasLimit())
self.data.number = self.env.BlockNumber().Uint64()
self.data.timestamp = self.env.Time()
self.data.code = getDataPtr(code)
self.data.codeSize = uint64(len(code))
self.data.codeHash = hash2llvm(crypto.Keccak256(code)) // TODO: Get already computed hash?
jit := C.evmjit_create()
retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self))
if retCode < 0 {
err = errors.New("OOG from JIT")
gas.SetInt64(0) // Set gas to 0, JIT does not bother
} else {
gas.SetInt64(self.data.gas)
if retCode == 1 { // RETURN
ret = C.GoBytes(unsafe.Pointer(self.data.callData), C.int(self.data.callDataSize))
} else if retCode == 2 { // SUICIDE
// TODO: Suicide support logic should be moved to Env to be shared by VM implementations
state := self.Env().State()
receiverAddr := llvm2hashRef(bswap(&self.data.address))
receiver := state.GetOrNewStateObject(receiverAddr)
balance := state.GetBalance(me.Address())
receiver.AddBalance(balance)
state.Delete(me.Address())
}
}
C.evmjit_destroy(jit)
return
}
func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine {
return self
}
func (self *JitVm) Endl() VirtualMachine {
return self
}
func (self *JitVm) Env() EVM {
return self.env
}
//export env_sha3
func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) {
data := llvm2bytesRef(dataPtr, length)
hash := crypto.Keccak256(data)
result := (*i256)(resultPtr)
*result = hash2llvm(hash)
}
//export env_sstore
func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) {
vm := (*JitVm)(vmPtr)
index := llvm2hash(bswap((*i256)(indexPtr)))
value := llvm2hash(bswap((*i256)(valuePtr)))
value = trim(value)
if len(value) == 0 {
prevValue := vm.env.State().GetState(vm.me.Address(), index)
if len(prevValue) != 0 {
vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund)
}
}
vm.env.State().SetState(vm.me.Address(), index, value)
}
//export env_sload
func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) {
vm := (*JitVm)(vmPtr)
index := llvm2hash(bswap((*i256)(indexPtr)))
value := vm.env.State().GetState(vm.me.Address(), index)
result := (*i256)(resultPtr)
*result = hash2llvm(value)
bswap(result)
}
//export env_balance
func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) {
vm := (*JitVm)(_vm)
addr := llvm2hash((*i256)(_addr))
balance := vm.Env().State().GetBalance(addr)
result := (*i256)(_result)
*result = big2llvm(balance)
}
//export env_blockhash
func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) {
vm := (*JitVm)(_vm)
number := llvm2big((*i256)(_number))
result := (*i256)(_result)
currNumber := vm.Env().BlockNumber()
limit := big.NewInt(0).Sub(currNumber, big.NewInt(256))
if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 {
hash := vm.Env().GetHash(uint64(number.Int64()))
*result = hash2llvm(hash)
} else {
*result = i256{}
}
}
//export env_call
func env_call(_vm unsafe.Pointer, _gas *int64, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
vm := (*JitVm)(_vm)
//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r)
}
}()
balance := vm.Env().State().GetBalance(vm.me.Address())
value := llvm2big((*i256)(_value))
if balance.Cmp(value) >= 0 {
receiveAddr := llvm2hash((*i256)(_receiveAddr))
inData := C.GoBytes(inDataPtr, C.int(inDataLen))
outData := llvm2bytesRef(outDataPtr, outDataLen)
codeAddr := llvm2hash((*i256)(_codeAddr))
gas := big.NewInt(*_gas)
var out []byte
var err error
if bytes.Equal(codeAddr, receiveAddr) {
out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value)
} else {
out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
}
*_gas = gas.Int64()
if err == nil {
copy(outData, out)
return true
}
}
return false
}
//export env_create
func env_create(_vm unsafe.Pointer, _gas *int64, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
vm := (*JitVm)(_vm)
value := llvm2big((*i256)(_value))
initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance
result := (*i256)(_result)
*result = i256{}
gas := big.NewInt(*_gas)
ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
if suberr == nil {
dataGas := big.NewInt(int64(len(ret))) // TODO: Not the best design. env.Create can do it, it has the reference to gas counter
dataGas.Mul(dataGas, params.CreateDataGas)
gas.Sub(gas, dataGas)
*result = hash2llvm(ref.Address())
}
*_gas = gas.Int64()
}
//export env_log
func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) {
vm := (*JitVm)(_vm)
data := C.GoBytes(dataPtr, C.int(dataLen))
topics := make([][]byte, 0, 4)
if _topic1 != nil {
topics = append(topics, llvm2hash((*i256)(_topic1)))
}
if _topic2 != nil {
topics = append(topics, llvm2hash((*i256)(_topic2)))
}
if _topic3 != nil {
topics = append(topics, llvm2hash((*i256)(_topic3)))
}
if _topic4 != nil {
topics = append(topics, llvm2hash((*i256)(_topic4)))
}
vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data, vm.env.BlockNumber().Uint64()))
}
//export env_extcode
func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte {
vm := (*JitVm)(_vm)
addr := llvm2hash((*i256)(_addr))
code := vm.Env().State().GetCode(addr)
*o_size = uint64(len(code))
return getDataPtr(code)
}*/

View file

@ -1,19 +0,0 @@
// 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/>.
// +build !evmjit
package vm

View file

@ -230,7 +230,7 @@ func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte,
// symDecrypt carries out CTR decryption using the block cipher specified in // symDecrypt carries out CTR decryption using the block cipher specified in
// the parameters // the parameters
func symDecrypt(rand io.Reader, params *ECIESParams, key, ct []byte) (m []byte, err error) { func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
c, err := params.Cipher(key) c, err := params.Cipher(key)
if err != nil { if err != nil {
return return
@ -292,7 +292,7 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e
} }
// Decrypt decrypts an ECIES ciphertext. // Decrypt decrypts an ECIES ciphertext.
func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) { func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
if len(c) == 0 { if len(c) == 0 {
return nil, ErrInvalidMessage return nil, ErrInvalidMessage
} }
@ -361,6 +361,6 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err
return return
} }
m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd]) m, err = symDecrypt(params, Ke, c[mStart:mEnd])
return return
} }

View file

@ -270,7 +270,7 @@ func TestEncryptDecrypt(t *testing.T) {
t.FailNow() t.FailNow()
} }
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
t.FailNow() t.FailNow()
@ -281,7 +281,7 @@ func TestEncryptDecrypt(t *testing.T) {
t.FailNow() t.FailNow()
} }
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil) _, err = prv1.Decrypt(ct, nil, nil)
if err == nil { if err == nil {
fmt.Println("ecies: encryption should not have succeeded") fmt.Println("ecies: encryption should not have succeeded")
t.FailNow() t.FailNow()
@ -301,7 +301,7 @@ func TestDecryptShared2(t *testing.T) {
} }
// Check that decrypting with correct shared data works. // Check that decrypting with correct shared data works.
pt, err := prv.Decrypt(rand.Reader, ct, nil, shared2) pt, err := prv.Decrypt(ct, nil, shared2)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -310,10 +310,10 @@ func TestDecryptShared2(t *testing.T) {
} }
// Decrypting without shared data or incorrect shared data fails. // Decrypting without shared data or incorrect shared data fails.
if _, err = prv.Decrypt(rand.Reader, ct, nil, nil); err == nil { if _, err = prv.Decrypt(ct, nil, nil); err == nil {
t.Fatal("ecies: decrypting without shared data didn't fail") t.Fatal("ecies: decrypting without shared data didn't fail")
} }
if _, err = prv.Decrypt(rand.Reader, ct, nil, []byte("garbage")); err == nil { if _, err = prv.Decrypt(ct, nil, []byte("garbage")); err == nil {
t.Fatal("ecies: decrypting with incorrect shared data didn't fail") t.Fatal("ecies: decrypting with incorrect shared data didn't fail")
} }
} }
@ -381,7 +381,7 @@ func testParamSelection(t *testing.T, c testCase) {
t.FailNow() t.FailNow()
} }
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil { if err != nil {
fmt.Printf("%s (%s)\n", err.Error(), c.Name) fmt.Printf("%s (%s)\n", err.Error(), c.Name)
t.FailNow() t.FailNow()
@ -393,7 +393,7 @@ func testParamSelection(t *testing.T, c testCase) {
t.FailNow() t.FailNow()
} }
_, err = prv1.Decrypt(rand.Reader, ct, nil, nil) _, err = prv1.Decrypt(ct, nil, nil)
if err == nil { if err == nil {
fmt.Printf("ecies: encryption should not have succeeded (%s)\n", fmt.Printf("ecies: encryption should not have succeeded (%s)\n",
c.Name) c.Name)
@ -422,7 +422,7 @@ func TestBasicKeyValidation(t *testing.T) {
for _, b := range badBytes { for _, b := range badBytes {
ct[0] = b ct[0] = b
_, err := prv.Decrypt(rand.Reader, ct, nil, nil) _, err := prv.Decrypt(ct, nil, nil)
if err != ErrInvalidPublicKey { if err != ErrInvalidPublicKey {
fmt.Println("ecies: validated an invalid key") fmt.Println("ecies: validated an invalid key")
t.FailNow() t.FailNow()
@ -441,14 +441,14 @@ func TestBox(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.Equal(pt, message) { if !bytes.Equal(pt, message) {
t.Fatal("ecies: plaintext doesn't match message") t.Fatal("ecies: plaintext doesn't match message")
} }
if _, err = prv1.Decrypt(rand.Reader, ct, nil, nil); err == nil { if _, err = prv1.Decrypt(ct, nil, nil); err == nil {
t.Fatal("ecies: encryption should not have succeeded") t.Fatal("ecies: encryption should not have succeeded")
} }
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/syndtr/goleveldb/leveldb/filter" "github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt" "github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/util"
) )
var OpenFileLimit = 64 var OpenFileLimit = 64
@ -121,6 +122,11 @@ func (db *LDBDatabase) NewIterator() iterator.Iterator {
return db.db.NewIterator(nil, nil) return db.db.NewIterator(nil, nil)
} }
// NewIteratorWithPrefix returns a iterator to iterate over subset of database content with a particular prefix.
func (db *LDBDatabase) NewIteratorWithPrefix(prefix []byte) iterator.Iterator {
return db.db.NewIterator(util.BytesPrefix(prefix), nil)
}
func (db *LDBDatabase) Close() { func (db *LDBDatabase) Close() {
// Stop the metrics collection to avoid internal database races // Stop the metrics collection to avoid internal database races
db.quitLock.Lock() db.quitLock.Lock()

View file

@ -58,18 +58,18 @@ type trustedCheckpoint struct {
var ( var (
mainnetCheckpoint = trustedCheckpoint{ mainnetCheckpoint = trustedCheckpoint{
name: "mainnet", name: "mainnet",
sectionIdx: 157, sectionIdx: 161,
sectionHead: common.HexToHash("1963c080887ca7f406c2bb114293eea83e54f783f94df24b447f7e3b6317c747"), sectionHead: common.HexToHash("75b0c4baa7a62cece48abdcb03b6f31601961c9bece67dcd61df87aad4fc0d8d"),
chtRoot: common.HexToHash("42abc436567dfb678a38fa6a9f881aa4c8a4cc8eaa2def08359292c3d0bd48ec"), chtRoot: common.HexToHash("bbbfaa67b29716348997ec21a39c03b8d1fb973f6a43740b865595ba26ee812f"),
bloomTrieRoot: common.HexToHash("281c9f8fb3cb8b37ae45e9907ef8f3b19cd22c54e297c2d6c09c1db1593dce42"), bloomTrieRoot: common.HexToHash("d6db6e6248354d7453391ce97830072a28ea4216be0bd95a5db9f53b1a64677b"),
} }
ropstenCheckpoint = trustedCheckpoint{ ropstenCheckpoint = trustedCheckpoint{
name: "ropsten", name: "ropsten",
sectionIdx: 83, sectionIdx: 87,
sectionHead: common.HexToHash("3ca623586bc0da35f1fc8d9b6b55950f3b1f69be9c6501846a2df672adb61236"), sectionHead: common.HexToHash("ebc0adcb30ed21cbe95bd77499cc1af0bada621fee3644cb80dbcf1444c123fe"),
chtRoot: common.HexToHash("8f08ec7783969768c6ef06e5fe3398223cbf4ae2907b676da7b6fe6c7f55b059"), chtRoot: common.HexToHash("d9830f4893c821ddf149b8cb9d3e3bfe3109d2eea8e3c4a4ede7c8b2ee8a7800"),
bloomTrieRoot: common.HexToHash("02d86d3c6a87f8f8a92c2a59bbba2132ff6f9f61b0915a5dc28a9d8279219fd0"), bloomTrieRoot: common.HexToHash("c76e12d713f65b84c5a36d06bc77d0c8419248ea0b36e0812a78b76aa6da0ddb"),
} }
) )

View file

@ -34,7 +34,7 @@ import (
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
) )
// NodeConfig represents the collection of configuration values to fine tune the Geth // NodeConfig represents the collection of configuration values to fine tune the Geth

View file

@ -491,7 +491,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r
} }
// Attempt decoding pre-EIP-8 "plain" format. // Attempt decoding pre-EIP-8 "plain" format.
key := ecies.ImportECDSA(prv) key := ecies.ImportECDSA(prv)
if dec, err := key.Decrypt(rand.Reader, buf, nil, nil); err == nil { if dec, err := key.Decrypt(buf, nil, nil); err == nil {
msg.decodePlain(dec) msg.decodePlain(dec)
return buf, nil return buf, nil
} }
@ -505,7 +505,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r
if _, err := io.ReadFull(r, buf[plainSize:]); err != nil { if _, err := io.ReadFull(r, buf[plainSize:]); err != nil {
return buf, err return buf, err
} }
dec, err := key.Decrypt(rand.Reader, buf[2:], nil, prefix) dec, err := key.Decrypt(buf[2:], nil, prefix)
if err != nil { if err != nil {
return buf, err return buf, err
} }

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release VersionMinor = 8 // Minor version component of the current release
VersionPatch = 3 // Patch version component of the current release VersionPatch = 4 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -169,7 +169,8 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// All checks passed, create a codec that reads direct from the request body // All checks passed, create a codec that reads direct from the request body
// untilEOF and writes the response to w and order the server to process a // untilEOF and writes the response to w and order the server to process a
// single request. // single request.
codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w}) body := io.LimitReader(r.Body, maxRequestContentLength)
codec := NewJSONCodec(&httpReadWriteNopCloser{body, w})
defer codec.Close() defer codec.Close()
w.Header().Set("content-type", contentType) w.Header().Set("content-type", contentType)

View file

@ -22,10 +22,10 @@ import (
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
) )
// Client defines typed wrappers for the Whisper v5 RPC API. // Client defines typed wrappers for the Whisper v6 RPC API.
type Client struct { type Client struct {
c *rpc.Client c *rpc.Client
} }
@ -168,27 +168,27 @@ func (sc *Client) Post(ctx context.Context, message whisper.NewMessage) error {
// SubscribeMessages subscribes to messages that match the given criteria. This method // SubscribeMessages subscribes to messages that match the given criteria. This method
// is only supported on bi-directional connections such as websockets and IPC. // is only supported on bi-directional connections such as websockets and IPC.
// NewMessageFilter uses polling and is supported over HTTP. // NewMessageFilter uses polling and is supported over HTTP.
func (ec *Client) SubscribeMessages(ctx context.Context, criteria whisper.Criteria, ch chan<- *whisper.Message) (ethereum.Subscription, error) { func (sc *Client) SubscribeMessages(ctx context.Context, criteria whisper.Criteria, ch chan<- *whisper.Message) (ethereum.Subscription, error) {
return ec.c.ShhSubscribe(ctx, ch, "messages", criteria) return sc.c.ShhSubscribe(ctx, ch, "messages", criteria)
} }
// NewMessageFilter creates a filter within the node. This filter can be used to poll // NewMessageFilter creates a filter within the node. This filter can be used to poll
// for new messages (see FilterMessages) that satisfy the given criteria. A filter can // for new messages (see FilterMessages) that satisfy the given criteria. A filter can
// timeout when it was polled for in whisper.filterTimeout. // timeout when it was polled for in whisper.filterTimeout.
func (ec *Client) NewMessageFilter(ctx context.Context, criteria whisper.Criteria) (string, error) { func (sc *Client) NewMessageFilter(ctx context.Context, criteria whisper.Criteria) (string, error) {
var id string var id string
return id, ec.c.CallContext(ctx, &id, "shh_newMessageFilter", criteria) return id, sc.c.CallContext(ctx, &id, "shh_newMessageFilter", criteria)
} }
// DeleteMessageFilter removes the filter associated with the given id. // DeleteMessageFilter removes the filter associated with the given id.
func (ec *Client) DeleteMessageFilter(ctx context.Context, id string) error { func (sc *Client) DeleteMessageFilter(ctx context.Context, id string) error {
var ignored bool var ignored bool
return ec.c.CallContext(ctx, &ignored, "shh_deleteMessageFilter", id) return sc.c.CallContext(ctx, &ignored, "shh_deleteMessageFilter", id)
} }
// FilterMessages retrieves all messages that are received between the last call to // FilterMessages retrieves all messages that are received between the last call to
// this function and match the criteria that where given when the filter was created. // this function and match the criteria that where given when the filter was created.
func (ec *Client) FilterMessages(ctx context.Context, id string) ([]*whisper.Message, error) { func (sc *Client) FilterMessages(ctx context.Context, id string) ([]*whisper.Message, error) {
var messages []*whisper.Message var messages []*whisper.Message
return messages, ec.c.CallContext(ctx, &messages, "shh_getFilterMessages", id) return messages, sc.c.CallContext(ctx, &messages, "shh_getFilterMessages", id)
} }

View file

@ -277,7 +277,7 @@ func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
// decryptAsymmetric decrypts an encrypted payload with a private key. // decryptAsymmetric decrypts an encrypted payload with a private key.
func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil) decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
if err == nil { if err == nil {
msg.Raw = decrypted msg.Raw = decrypted
} }

View file

@ -558,9 +558,10 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
} }
if len(req.Topics) > 0 { if len(req.Topics) > 0 {
topics = make([][]byte, 0, len(req.Topics)) topics = make([][]byte, len(req.Topics))
for _, topic := range req.Topics { for i, topic := range req.Topics {
topics = append(topics, topic[:]) topics[i] = make([]byte, TopicLength)
copy(topics[i], topic[:])
} }
} }

View file

@ -0,0 +1,78 @@
// 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/>.
package whisperv6
import (
"bytes"
"crypto/ecdsa"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
set "gopkg.in/fatih/set.v0"
)
func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) {
w := &Whisper{
privateKeys: make(map[string]*ecdsa.PrivateKey),
symKeys: make(map[string][]byte),
envelopes: make(map[common.Hash]*Envelope),
expirations: make(map[uint32]*set.SetNonTS),
peers: make(map[*Peer]struct{}),
messageQueue: make(chan *Envelope, messageQueueLimit),
p2pMsgQueue: make(chan *Envelope, messageQueueLimit),
quit: make(chan struct{}),
syncAllowance: DefaultSyncAllowance,
}
w.filters = NewFilters(w)
keyID, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("Error generating symmetric key: %v", err)
}
api := PublicWhisperAPI{
w: w,
lastUsed: make(map[string]time.Time),
}
t1 := [4]byte{0xde, 0xea, 0xbe, 0xef}
t2 := [4]byte{0xca, 0xfe, 0xde, 0xca}
crit := Criteria{
SymKeyID: keyID,
Topics: []TopicType{TopicType(t1), TopicType(t2)},
}
_, err = api.NewMessageFilter(crit)
if err != nil {
t.Fatalf("Error creating the filter: %v", err)
}
found := false
candidates := w.filters.getWatchersByTopic(TopicType(t1))
for _, f := range candidates {
if len(f.Topics) == 2 {
if bytes.Equal(f.Topics[0], t1[:]) && bytes.Equal(f.Topics[1], t2[:]) {
found = true
}
}
}
if !found {
t.Fatalf("Could not find filter with both topics")
}
}

View file

@ -289,7 +289,7 @@ func (msg *ReceivedMessage) decryptSymmetric(key []byte) error {
// decryptAsymmetric decrypts an encrypted payload with a private key. // decryptAsymmetric decrypts an encrypted payload with a private key.
func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
decrypted, err := ecies.ImportECDSA(key).Decrypt(crand.Reader, msg.Raw, nil, nil) decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
if err == nil { if err == nil {
msg.Raw = decrypted msg.Raw = decrypted
} }