diff options
-rw-r--r-- | cmd/geth/chaincmd.go | 62 | ||||
-rw-r--r-- | cmd/geth/main.go | 2 | ||||
-rw-r--r-- | cmd/puppeth/puppeth.go | 7 | ||||
-rw-r--r-- | cmd/utils/cmd.go | 94 | ||||
-rw-r--r-- | core/asm/compiler.go | 2 | ||||
-rw-r--r-- | core/evm.go | 19 | ||||
-rw-r--r-- | core/headerchain.go | 2 | ||||
-rw-r--r-- | core/state/statedb.go | 4 | ||||
-rw-r--r-- | core/vm/doc.go | 17 | ||||
-rw-r--r-- | core/vm/evm.go | 6 | ||||
-rw-r--r-- | core/vm/instructions.go | 171 | ||||
-rw-r--r-- | core/vm/instructions_test.go | 6 | ||||
-rw-r--r-- | core/vm/interpreter.go | 6 | ||||
-rw-r--r-- | core/vm/intpool.go | 16 | ||||
-rw-r--r-- | core/vm/logger_test.go | 2 | ||||
-rw-r--r-- | core/vm/runtime/runtime.go | 4 | ||||
-rw-r--r-- | core/vm/vm_jit.go | 389 | ||||
-rw-r--r-- | core/vm/vm_jit_fake.go | 19 | ||||
-rw-r--r-- | crypto/ecies/ecies.go | 6 | ||||
-rw-r--r-- | crypto/ecies/ecies_test.go | 20 | ||||
-rw-r--r-- | ethdb/database.go | 6 | ||||
-rw-r--r-- | p2p/rlpx.go | 4 | ||||
-rw-r--r-- | rpc/http.go | 3 | ||||
-rw-r--r-- | whisper/whisperv5/message.go | 2 | ||||
-rw-r--r-- | whisper/whisperv6/message.go | 2 |
25 files changed, 307 insertions, 564 deletions
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c9ab72b6d..d3086921b 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -96,6 +96,34 @@ Optional second and third arguments control the first and last block to write. In this mode, the file will be appended 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{ Action: utils.MigrateFlags(copyDb), Name: "copydb", @@ -299,7 +327,39 @@ func exportChain(ctx *cli.Context) error { if err != nil { 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 } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f5a3fa941..061384d1b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -155,6 +155,8 @@ func init() { initCommand, importCommand, exportCommand, + importPreimagesCommand, + exportPreimagesCommand, copydbCommand, removedbCommand, dumpCommand, diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go index 26382dac1..f9b8fe481 100644 --- a/cmd/puppeth/puppeth.go +++ b/cmd/puppeth/puppeth.go @@ -20,6 +20,7 @@ package main import ( "math/rand" "os" + "strings" "time" "github.com/ethereum/go-ethereum/log" @@ -34,7 +35,7 @@ func main() { app.Flags = []cli.Flag{ cli.StringFlag{ Name: "network", - Usage: "name of the network to administer", + Usage: "name of the network to administer (no spaces or hyphens, please)", }, cli.IntFlag{ 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)))) 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 makeWizard(c.String("network")).run() return nil diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 186d18d8f..c0af4c13e 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -27,8 +27,11 @@ import ( "strings" "syscall" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "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/log" "github.com/ethereum/go-ethereum/node" @@ -105,6 +108,8 @@ func ImportChain(chain *core.BlockChain, fn string) error { } log.Info("Importing blockchain", "file", fn) + + // Open the file handle and potentially unwrap the gzip stream fh, err := os.Open(fn) if err != nil { return err @@ -180,8 +185,12 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block 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 { 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) if err != nil { return err @@ -193,7 +202,7 @@ func ExportChain(blockchain *core.BlockChain, fn string) error { writer = gzip.NewWriter(writer) defer writer.(*gzip.Writer).Close() } - + // Iterate over the blocks and export them if err := blockchain.Export(writer); err != nil { return err } @@ -202,9 +211,12 @@ func ExportChain(blockchain *core.BlockChain, fn string) error { 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 { 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) if err != nil { return err @@ -216,10 +228,86 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las writer = gzip.NewWriter(writer) defer writer.(*gzip.Writer).Close() } - + // Iterate over the blocks and export them if err := blockchain.ExportN(writer, first, last); err != nil { return err } log.Info("Exported blockchain to", "file", fn) 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 +} diff --git a/core/asm/compiler.go b/core/asm/compiler.go index 1b9025a54..18dc0877f 100644 --- a/core/asm/compiler.go +++ b/core/asm/compiler.go @@ -114,7 +114,7 @@ func (c *Compiler) Compile() (string, []error) { } // next returns the next token and increments the -// posititon. +// position. func (c *Compiler) next() token { token := c.tokens[c.pos] c.pos++ diff --git a/core/evm.go b/core/evm.go index 55db53927..596ea95fb 100644 --- a/core/evm.go +++ b/core/evm.go @@ -60,13 +60,26 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author // GetHashFn returns a GetHashFunc which retrieves header hashes by number func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { + var cache map[uint64]common.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) { - if header.Number.Uint64() == n { - return header.Hash() + cache[header.Number.Uint64()-1] = header.ParentHash + if n == header.Number.Uint64()-1 { + return header.ParentHash } } - return common.Hash{} } } diff --git a/core/headerchain.go b/core/headerchain.go index 73cd5d2c4..2d1b0a2a1 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -23,6 +23,7 @@ import ( "math" "math/big" mrand "math/rand" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -32,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/hashicorp/golang-lru" - "sync/atomic" ) const ( diff --git a/core/state/statedb.go b/core/state/statedb.go index 776693e24..5473ff8da 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -83,7 +83,7 @@ type StateDB struct { 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) { tr, err := db.OpenTrie(root) if err != nil { @@ -110,7 +110,7 @@ func (self *StateDB) Error() error { 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. func (self *StateDB) Reset(root common.Hash) error { tr, err := self.db.OpenTrie(root) diff --git a/core/vm/doc.go b/core/vm/doc.go index 239be2cfe..5864d0cfa 100644 --- a/core/vm/doc.go +++ b/core/vm/doc.go @@ -17,19 +17,8 @@ /* Package vm implements the Ethereum Virtual Machine. -The vm package implements two EVMs, a byte code VM and a JIT VM. The BC -(Byte Code) VM loops over a set of bytes and executes them according to the set -of rules defined in the Ethereum yellow paper. When the BC VM is invoked it -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. +The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops +over a set of bytes and executes them according to the set of rules defined +in the Ethereum yellow paper. */ package vm diff --git a/core/vm/evm.go b/core/vm/evm.go index 46e7baff4..96676c314 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -111,7 +111,7 @@ type EVM struct { 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*. func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ @@ -221,7 +221,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, to = AccountRef(caller.Address()) ) // 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. contract := NewContract(caller, to, value, gas) 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) // 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. contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 66e804fb7..1e494a0eb 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -39,20 +39,18 @@ var ( ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Add(x, y))) - - evm.interpreter.intPool.put(y) + x, y := stack.pop(), stack.peek() + math.U256(y.Add(x, y)) + evm.interpreter.intPool.put(x) return nil, nil } func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Sub(x, y))) - - evm.interpreter.intPool.put(y) + x, y := stack.pop(), stack.peek() + math.U256(y.Sub(x, y)) + evm.interpreter.intPool.put(x) 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) { - x, y := stack.pop(), stack.pop() + x, y := stack.pop(), stack.peek() if y.Sign() != 0 { - stack.push(math.U256(x.Div(x, y))) + math.U256(y.Div(x, y)) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(y) - + evm.interpreter.intPool.put(x) return nil, nil } func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) - if y.Sign() == 0 { - stack.push(new(big.Int)) - return nil, nil + res := evm.interpreter.intPool.getZero() + + if y.Sign() == 0 || x.Sign() == 0 { + stack.push(res) } else { - n := new(big.Int) - if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 { - n.SetInt64(-1) + if x.Sign() != y.Sign() { + res.Div(x.Abs(x), y.Abs(y)) + res.Neg(res) } 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)) } - evm.interpreter.intPool.put(y) + evm.interpreter.intPool.put(x, y) return nil, nil } func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Sign() == 0 { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } else { 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) { x, y := math.S256(stack.pop()), math.S256(stack.pop()) + res := evm.interpreter.intPool.getZero() if y.Sign() == 0 { - stack.push(new(big.Int)) + stack.push(res) } else { - n := new(big.Int) if x.Sign() < 0 { - n.SetInt64(-1) + res.Mod(x.Abs(x), y.Abs(y)) + res.Neg(res) } 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)) } - evm.interpreter.intPool.put(y) + evm.interpreter.intPool.put(x, y) 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) { - x := stack.pop() - stack.push(math.U256(x.Not(x))) + 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) { - x, y := stack.pop(), stack.pop() + x, y := stack.pop(), stack.peek() if x.Cmp(y) < 0 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + y.SetUint64(1) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(x, y) + evm.interpreter.intPool.put(x) return nil, nil } 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 { - stack.push(evm.interpreter.intPool.get().SetUint64(1)) + y.SetUint64(1) } else { - stack.push(new(big.Int)) + y.SetUint64(0) } - - evm.interpreter.intPool.put(x, y) + evm.interpreter.intPool.put(x) 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) { - x, y := stack.pop(), stack.pop() - stack.push(x.Or(x, y)) + x, y := stack.pop(), stack.peek() + y.Or(x, y) - evm.interpreter.intPool.put(y) + evm.interpreter.intPool.put(x) return nil, nil } func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(x.Xor(x, y)) + x, y := stack.pop(), stack.peek() + y.Xor(x, y) - evm.interpreter.intPool.put(y) + evm.interpreter.intPool.put(x) 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) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { - add := x.Add(x, y) - add.Mod(add, z) - stack.push(math.U256(add)) + x.Add(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) } else { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } - evm.interpreter.intPool.put(y, z) 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) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(bigZero) > 0 { - mul := x.Mul(x, y) - mul.Mod(mul, z) - stack.push(math.U256(mul)) + x.Mul(x, y) + x.Mod(x, z) + stack.push(math.U256(x)) } else { - stack.push(new(big.Int)) + stack.push(x.SetUint64(0)) } - evm.interpreter.intPool.put(y, z) return nil, nil } @@ -393,8 +379,7 @@ func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta if evm.vmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(common.BytesToHash(hash), data) } - - stack.push(new(big.Int).SetBytes(hash)) + stack.push(evm.interpreter.intPool.get().SetBytes(hash)) evm.interpreter.intPool.put(offset, size) 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) { - addr := common.BigToAddress(stack.pop()) - balance := evm.StateDB.GetBalance(addr) - - stack.push(new(big.Int).Set(balance)) + slot := stack.peek() + slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot))) 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) { - 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 } @@ -460,10 +443,11 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, memOffset = stack.pop() dataOffset = stack.pop() length = stack.pop() + + end = evm.interpreter.intPool.get().Add(dataOffset, length) ) - defer evm.interpreter.intPool.put(memOffset, dataOffset, length) + defer evm.interpreter.intPool.put(memOffset, dataOffset, length, end) - end := new(big.Int).Add(dataOffset, length) if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() { 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) { - a := stack.pop() - - addr := common.BigToAddress(a) - a.SetInt64(int64(evm.StateDB.GetCodeSize(addr))) - stack.push(a) + slot := stack.peek() + slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) 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) { l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code))) stack.push(l) + 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 { stack.push(evm.GetHash(num.Uint64()).Big()) } else { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } - evm.interpreter.intPool.put(num, n) 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) { - stack.push(math.U256(new(big.Int).Set(evm.Time))) + stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Time))) return nil, nil } 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 } 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 } 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 } @@ -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) { 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) 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 // ignore this error and pretend the operation was successful. 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 { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } else { 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) if err != nil { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { 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) if err != nil { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { 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) if err != nil { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { 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) if err != nil { - stack.push(new(big.Int)) + stack.push(evm.interpreter.intPool.getZero()) } else { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 134363bb7..0de558612 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -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)) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) stack = newstack() pc = uint64(0) ) @@ -68,7 +68,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64 func TestByteOp(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) stack = newstack() ) 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) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) stack = newstack() ) // convert args diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 95490adfc..47d5e7f2f 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -28,10 +28,6 @@ import ( type Config struct { // Debug enabled debugging Interpreter options Debug bool - // EnableJit enabled the JIT VM - EnableJit bool - // ForceJit forces the JIT VM - ForceJit bool // Tracer is the op code logger Tracer Tracer // NoRecursion disabled Interpreter call, callcode, @@ -47,7 +43,7 @@ type Config struct { // Interpreter is used to run Ethereum based contracts and will utilise the // passed evmironment 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. type Interpreter struct { evm *EVM diff --git a/core/vm/intpool.go b/core/vm/intpool.go index 384f5df59..5dbda18ee 100644 --- a/core/vm/intpool.go +++ b/core/vm/intpool.go @@ -32,24 +32,36 @@ func newIntPool() *intPool { 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 { if p.pool.len() > 0 { return p.pool.pop() } 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) { if len(p.pool.data) > poolLimit { return } - for _, i := range is { // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if verifyPool { i.Set(checkVal) } - p.pool.push(i) } } diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 915f7177e..28830c445 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -48,7 +48,7 @@ type dummyStateDB struct { func TestStoreCapture(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) logger = NewStructLogger(nil) mem = NewMemory() stack = newstack() diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index edbf54176..1e9ed7ae2 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -41,7 +41,6 @@ type Config struct { GasLimit uint64 GasPrice *big.Int Value *big.Int - DisableJit bool // "disable" so it's enabled by default Debug bool 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. // // 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 -// to it's original state afterwards. +// the given code. It makes sure that it's restored to it's original state afterwards. func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { if cfg == nil { cfg = new(Config) diff --git a/core/vm/vm_jit.go b/core/vm/vm_jit.go deleted file mode 100644 index eb3acfb10..000000000 --- a/core/vm/vm_jit.go +++ /dev/null @@ -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) -}*/ diff --git a/core/vm/vm_jit_fake.go b/core/vm/vm_jit_fake.go deleted file mode 100644 index 44b60abf6..000000000 --- a/core/vm/vm_jit_fake.go +++ /dev/null @@ -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 diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 2ed91c895..147418148 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -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 // 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) if err != nil { 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. -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 { return nil, ErrInvalidMessage } @@ -361,6 +361,6 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err return } - m, err = symDecrypt(rand, params, Ke, c[mStart:mEnd]) + m, err = symDecrypt(params, Ke, c[mStart:mEnd]) return } diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 9cd5c79f7..f33f204d5 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -270,7 +270,7 @@ func TestEncryptDecrypt(t *testing.T) { t.FailNow() } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { fmt.Println(err.Error()) t.FailNow() @@ -281,7 +281,7 @@ func TestEncryptDecrypt(t *testing.T) { t.FailNow() } - _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) + _, err = prv1.Decrypt(ct, nil, nil) if err == nil { fmt.Println("ecies: encryption should not have succeeded") t.FailNow() @@ -301,7 +301,7 @@ func TestDecryptShared2(t *testing.T) { } // 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 { t.Fatal(err) } @@ -310,10 +310,10 @@ func TestDecryptShared2(t *testing.T) { } // 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") } - 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") } } @@ -381,7 +381,7 @@ func testParamSelection(t *testing.T, c testCase) { t.FailNow() } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { fmt.Printf("%s (%s)\n", err.Error(), c.Name) t.FailNow() @@ -393,7 +393,7 @@ func testParamSelection(t *testing.T, c testCase) { t.FailNow() } - _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) + _, err = prv1.Decrypt(ct, nil, nil) if err == nil { fmt.Printf("ecies: encryption should not have succeeded (%s)\n", c.Name) @@ -422,7 +422,7 @@ func TestBasicKeyValidation(t *testing.T) { for _, b := range badBytes { ct[0] = b - _, err := prv.Decrypt(rand.Reader, ct, nil, nil) + _, err := prv.Decrypt(ct, nil, nil) if err != ErrInvalidPublicKey { fmt.Println("ecies: validated an invalid key") t.FailNow() @@ -441,14 +441,14 @@ func TestBox(t *testing.T) { t.Fatal(err) } - pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) + pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { t.Fatal(err) } if !bytes.Equal(pt, 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") } } diff --git a/ethdb/database.go b/ethdb/database.go index 8c557e482..30ed37dc7 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -29,6 +29,7 @@ import ( "github.com/syndtr/goleveldb/leveldb/filter" "github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/opt" + "github.com/syndtr/goleveldb/leveldb/util" ) var OpenFileLimit = 64 @@ -121,6 +122,11 @@ func (db *LDBDatabase) NewIterator() iterator.Iterator { 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() { // Stop the metrics collection to avoid internal database races db.quitLock.Lock() diff --git a/p2p/rlpx.go b/p2p/rlpx.go index 1889edac9..a320e81e7 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -491,7 +491,7 @@ func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r } // Attempt decoding pre-EIP-8 "plain" format. 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) 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 { return buf, err } - dec, err := key.Decrypt(rand.Reader, buf[2:], nil, prefix) + dec, err := key.Decrypt(buf[2:], nil, prefix) if err != nil { return buf, err } diff --git a/rpc/http.go b/rpc/http.go index 9805d69b6..e8f51150f 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -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 // untilEOF and writes the response to w and order the server to process a // single request. - codec := NewJSONCodec(&httpReadWriteNopCloser{r.Body, w}) + body := io.LimitReader(r.Body, maxRequestContentLength) + codec := NewJSONCodec(&httpReadWriteNopCloser{body, w}) defer codec.Close() w.Header().Set("content-type", contentType) diff --git a/whisper/whisperv5/message.go b/whisper/whisperv5/message.go index c27535cd1..34ce52e64 100644 --- a/whisper/whisperv5/message.go +++ b/whisper/whisperv5/message.go @@ -277,7 +277,7 @@ func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error { // decryptAsymmetric decrypts an encrypted payload with a private key. 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 { msg.Raw = decrypted } diff --git a/whisper/whisperv6/message.go b/whisper/whisperv6/message.go index b8318cbe8..2d4e86244 100644 --- a/whisper/whisperv6/message.go +++ b/whisper/whisperv6/message.go @@ -289,7 +289,7 @@ func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { // decryptAsymmetric decrypts an encrypted payload with a private key. 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 { msg.Raw = decrypted } |