Commit 269cfbb8 authored by Felix Lange's avatar Felix Lange

Merge branch origin/develop into accounts-integration

Conflicts:
	cmd/blocktest/main.go
	cmd/mist/debugger.go
	cmd/utils/cmd.go
parents 972e2c1e 0542df94
......@@ -187,6 +187,9 @@ func loadBlocksFromTestFile(filePath string) (blocks types.Blocks, err error) {
}
gb := types.NewBlockWithHeader(gbh)
//gb.uncles = *new([]*types.Header)
//gb.transactions = *new(types.Transactions)
gb.Td = new(big.Int)
gb.Reward = new(big.Int)
testBlock := new(types.Block)
......
......@@ -105,6 +105,11 @@ runtime will execute the file and exit.
Name: "import",
Usage: `import a blockchain file`,
},
{
Action: exportchain,
Name: "export",
Usage: `export blockchain into file`,
},
}
app.Flags = []cli.Flag{
utils.BootnodesFlag,
......@@ -232,25 +237,39 @@ func importchain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
chain, _, _ := utils.GetChain(ctx)
chainmgr, _, _ := utils.GetChain(ctx)
start := time.Now()
err := utils.ImportChain(chain, ctx.Args().First())
err := utils.ImportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Import error: %v\n", err)
}
fmt.Printf("Import done in", time.Since(start))
fmt.Printf("Import done in %v", time.Since(start))
return
}
func exportchain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
chainmgr, _, _ := utils.GetChain(ctx)
start := time.Now()
err := utils.ExportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v", time.Since(start))
return
}
func dump(ctx *cli.Context) {
chain, _, stateDb := utils.GetChain(ctx)
chainmgr, _, stateDb := utils.GetChain(ctx)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
block = chain.GetBlock(ethutil.Hex2Bytes(arg))
block = chainmgr.GetBlock(ethutil.Hex2Bytes(arg))
} else {
num, _ := strconv.Atoi(arg)
block = chain.GetBlockByNumber(uint64(num))
block = chainmgr.GetBlockByNumber(uint64(num))
}
if block == nil {
fmt.Println("{}")
......@@ -264,13 +283,15 @@ func dump(ctx *cli.Context) {
}
func version(c *cli.Context) {
fmt.Printf(`%v %v
PV=%d
GOOS=%s
GO=%s
fmt.Printf(`%v
Version: %v
Protocol Version: %d
Network Id: %d
GO: %s
OS: %s
GOPATH=%s
GOROOT=%s
`, ClientIdentifier, Version, eth.ProtocolVersion, runtime.GOOS, runtime.Version(), os.Getenv("GOPATH"), runtime.GOROOT())
`, ClientIdentifier, Version, eth.ProtocolVersion, eth.NetworkId, runtime.Version(), runtime.GOOS, os.Getenv("GOPATH"), runtime.GOROOT())
}
// hashish returns true for strings that look like hashes.
......
......@@ -199,13 +199,6 @@ ApplicationWindow {
Menu {
title: "Developer"
MenuItem {
iconSource: "../icecream.png"
text: "Debugger"
shortcut: "Ctrl+d"
onTriggered: eth.startDebugger()
}
MenuItem {
text: "Import Tx"
onTriggered: {
......@@ -761,24 +754,6 @@ ApplicationWindow {
}
}
Rectangle {
height: 55
color: "transparent"
visible: true
Text {
text: "DEBUG"
font.family: sourceSansPro.name
font.weight: Font.DemiBold
anchors {
left: parent.left
top: parent.verticalCenter
leftMargin: 16
}
color: "#AAA0A0"
}
}
ColumnLayout {
id: menuLegacy
visible: true
......
......@@ -178,7 +178,6 @@ Rectangle {
}
function showContractData(tx) {
txDetailsDebugButton.tx = tx
if(tx.createsContract) {
contractData.text = tx.data
contractLabel.text = "<h4> Transaction created contract " + tx.address + "</h4>"
......@@ -202,22 +201,6 @@ Rectangle {
id: contractLabel
anchors.leftMargin: 10
}
Button {
property var tx
id: txDetailsDebugButton
anchors.right: parent.right
anchors.rightMargin: 10
anchors.top: parent.top
anchors.topMargin: 10
text: "Debug contract"
onClicked: {
if(tx && tx.createsContract){
eth.startDbWithCode(tx.rawData)
}else {
eth.startDbWithContractAndData(tx.address, tx.rawData)
}
}
}
TextArea {
id: contractData
text: "Contract"
......
/*
This file is part of go-ethereum
go-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @authors
* Jeffrey Wilcke <i@jev.io>
*/
package main
import (
"fmt"
"math/big"
"strconv"
"strings"
"unicode"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
"github.com/obscuren/qml"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
vm *vm.Vm
Db *Debugger
state *state.StateDB
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
engine := qml.NewEngine()
component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
if err != nil {
fmt.Println(err)
return nil
}
win := component.CreateWindow(nil)
w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &vm.Vm{}}
w.Db = NewDebugger(w)
return w
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func (self *DebuggerWindow) SetCode(code string) {
self.win.Set("codeText", code)
}
func (self *DebuggerWindow) SetData(data string) {
self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data []byte) {
self.win.Root().Call("clearAsm")
dis := core.Disassemble(data)
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
}
func (self *DebuggerWindow) Compile(code string) {
var err error
script := ethutil.StringToByteFunc(code, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, true)
return
})
if err == nil {
self.SetAsm(script)
}
}
// Used by QML
func (self *DebuggerWindow) AutoComp(code string) {
if self.Db.done {
self.Compile(code)
}
}
func (self *DebuggerWindow) ClearLog() {
self.win.Root().Call("clearLog")
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
self.Stop()
defer func() {
if r := recover(); r != nil {
self.Logf("compile FAULT: %v", r)
}
}()
data := utils.FormatTransactionData(dataStr)
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, false)
return
})
if err != nil {
self.Logln(err)
return
}
// TODO: improve this
allAccounts, _ := self.lib.eth.AccountManager().Accounts()
var (
gas = ethutil.Big(gasStr)
gasPrice = ethutil.Big(gasPriceStr)
value = ethutil.Big(valueStr)
acc = allAccounts[0]
)
statedb := self.lib.eth.ChainManager().TransState()
account := self.lib.eth.ChainManager().TransState().GetAccount(acc.Address)
contract := statedb.NewStateObject([]byte{0})
contract.SetCode(script)
contract.SetBalance(value)
self.SetAsm(script)
block := self.lib.eth.ChainManager().CurrentBlock()
msg := types.NewTransactionMessage(nil, value, gas, gasPrice, data)
env := core.NewEnv(statedb, self.lib.eth.ChainManager(), msg, block)
self.Logf("callsize %d", len(script))
go func() {
pgas := new(big.Int).Set(gas)
ret, err := env.Call(account, contract.Address(), data, gas, gasPrice, ethutil.Big0)
rgas := new(big.Int).Sub(pgas, gas)
tot := new(big.Int).Mul(rgas, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", rgas, tot, ethutil.CurrencyToString(tot))
if err != nil {
self.Logln("exited with errors:", err)
} else {
if len(ret) > 0 {
self.Logf("exited: % x", ret)
} else {
self.Logf("exited: nil")
}
}
statedb.Reset()
if !self.Db.interrupt {
self.Db.done = true
} else {
self.Db.interrupt = false
}
}()
}
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}
func (self *DebuggerWindow) Logln(v ...interface{}) {
str := fmt.Sprintln(v...)
self.Logf("%s", str[:len(str)-1])
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
func (self *DebuggerWindow) Continue() {
self.vm.Stepping = false
self.Next()
}
func (self *DebuggerWindow) Stop() {
if !self.Db.done {
self.Db.Q <- true
}
}
func (self *DebuggerWindow) ExecCommand(command string) {
if len(command) > 0 {
cmd := strings.Split(command, " ")
switch cmd[0] {
case "help":
self.Logln("Debugger commands:")
self.Logln("break, bp Set breakpoint on instruction")
self.Logln("clear [log, break, bp] Clears previous set sub-command(s)")
case "break", "bp":
if len(cmd) > 1 {
lineNo, err := strconv.Atoi(cmd[1])
if err != nil {
self.Logln(err)
break
}
self.Db.breakPoints = append(self.Db.breakPoints, int64(lineNo))
self.Logf("break point set on instruction %d", lineNo)
} else {
self.Logf("'%s' requires line number", cmd[0])
}
case "clear":
if len(cmd) > 1 {
switch cmd[1] {
case "break", "bp":
self.Db.breakPoints = nil
self.Logln("Breakpoints cleared")
case "log":
self.ClearLog()
default:
self.Logf("clear '%s' is not valid", cmd[1])
}
} else {
self.Logln("'clear' requires sub command")
}
default:
self.Logf("Unknown command %s", cmd[0])
}
}
}
type Debugger struct {
N chan bool
Q chan bool
done, interrupt bool
breakPoints []int64
main *DebuggerWindow
win *qml.Window
}
func NewDebugger(main *DebuggerWindow) *Debugger {
db := &Debugger{make(chan bool), make(chan bool), true, false, nil, main, main.win}
return db
}
type storeVal struct {
Key, Value string
}
func (self *Debugger) Step(evm vm.VirtualMachine, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, context *vm.Context) {
}
func (self *Debugger) BreakHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
self.main.Logln("break on instr:", pc)
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) StepHook(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) SetCode(byteCode []byte) {
self.main.SetAsm(byteCode)
}
func (self *Debugger) BreakPoints() []int64 {
return self.breakPoints
}
func (d *Debugger) halting(pc int, op vm.OpCode, mem *vm.Memory, stack *vm.Stack, stateObject *state.StateObject) bool {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
d.win.Root().Call("clearStorage")
addr := 0
for i := 0; i+16 <= mem.Len(); i += 16 {
dat := mem.Data()[i : i+16]
var str string
for _, d := range dat {
if unicode.IsGraphic(rune(d)) {
str += string(d)
} else {
str += "?"
}
}
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("%s % x", str, dat)})
addr += 16
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
it := stateObject.Trie().Iterator()
for it.Next() {
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", it.Key), fmt.Sprintf("% x", it.Value)})
}
stackFrameAt := new(big.Int).SetBytes(mem.Get(0, 32))
psize := mem.Len() - int(new(big.Int).SetBytes(mem.Get(0, 32)).Uint64())
d.win.Root().ObjectByName("stackFrame").Set("text", fmt.Sprintf(`<b>stack ptr</b>: %v`, stackFrameAt))
d.win.Root().ObjectByName("stackSize").Set("text", fmt.Sprintf(`<b>stack size</b>: %d`, psize))
d.win.Root().ObjectByName("memSize").Set("text", fmt.Sprintf(`<b>mem size</b>: %v`, mem.Len()))
out:
for {
select {
case <-d.N:
break out
case <-d.Q:
d.interrupt = true
d.clearBuffers()
return false
}
}
return true
}
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}
......@@ -48,8 +48,6 @@ type UiLib struct {
assetPath string
// The main application window
win *qml.Window
Db *Debugger
DbWindow *DebuggerWindow
jsEngine *javascript.JSRE
......@@ -126,29 +124,6 @@ func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p)
}
func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self)
object := self.eth.ChainManager().State().GetStateObject(ethutil.Hex2Bytes(contractHash))
if len(object.Code()) > 0 {
dbWindow.SetCode(ethutil.Bytes2Hex(object.Code()))
}
dbWindow.SetData(data)
dbWindow.Show()
}
func (self *UiLib) StartDbWithCode(code string) {
dbWindow := NewDebuggerWindow(self)
dbWindow.SetCode(code)
dbWindow.Show()
}
func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self)
dbWindow.Show()
}
func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
object := mapToTxParams(params)
......
......@@ -33,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/state"
)
var clilogger = logger.NewLogger("CLI")
......@@ -123,6 +122,15 @@ func StartEthereum(ethereum *eth.Ethereum) {
})
}
func StartEthereumForTest(ethereum *eth.Ethereum) {
clilogger.Infoln("Starting ", ethereum.Name())
ethereum.StartForTest()
RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop()
logger.Flush()
})
}
func FormatTransactionData(data string) []byte {
d := ethutil.StringToByteFunc(data, func(s string) (ret []byte) {
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
......@@ -136,27 +144,8 @@ func FormatTransactionData(data string) []byte {
return d
}
// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
block := ethereum.ChainManager().GetBlock(hash)
if block == nil {
return fmt.Errorf("unknown block %x", hash)
}
parent := ethereum.ChainManager().GetBlock(block.ParentHash())
statedb := state.New(parent.Root(), ethereum.StateDb())
_, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true)
if err != nil {
return err
}
return nil
}
func ImportChain(chain *core.ChainManager, fn string) error {
fmt.Printf("importing chain '%s'\n", fn)
func ImportChain(chainmgr *core.ChainManager, fn string) error {
fmt.Printf("importing blockchain '%s'\n", fn)
fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
if err != nil {
return err
......@@ -168,11 +157,24 @@ func ImportChain(chain *core.ChainManager, fn string) error {
return err
}
chain.Reset()
if err := chain.InsertChain(blocks); err != nil {
chainmgr.Reset()
if err := chainmgr.InsertChain(blocks); err != nil {
return err
}
fmt.Printf("imported %d blocks\n", len(blocks))
return nil
}
func ExportChain(chainmgr *core.ChainManager, fn string) error {
fmt.Printf("exporting blockchain '%s'\n", fn)
data := chainmgr.Export()
if err := ethutil.WriteFile(fn, data); err != nil {
return err
}
fmt.Printf("exported blockchain\n")
return nil
}
......@@ -261,7 +261,7 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
}
if block.Time <= parent.Time {
return ValidationError("Block timestamp not after or equal to prev block (%v - %v)", block.Time, parent.Time)
return ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
}
if int64(block.Time) > time.Now().Unix() {
......
......@@ -260,6 +260,17 @@ func (s *Ethereum) Start() error {
return nil
}
func (s *Ethereum) StartForTest() {
jsonlogger.LogJson(&logger.LogStarting{
ClientString: s.net.Name,
ProtocolVersion: ProtocolVersion,
})
// Start services
s.txPool.Start()
s.blockPool.Start()
}
func (self *Ethereum) SuggestPeer(nodeURL string) error {
n, err := discover.ParseNode(nodeURL)
if err != nil {
......
package natspec
import (
"fmt"
"github.com/obscuren/otto"
"io/ioutil"
)
type NatSpec struct {
jsvm *otto.Otto
}
func NewNATSpec(transaction string) (self *NatSpec, err error) {
// TODO: should initialise with abi and userdoc jsons
func New() (self *NatSpec, err error) {
self = new(NatSpec)
self.jsvm = otto.New()
code, err := ioutil.ReadFile("natspec.js")
if err != nil {
return
}
_, err = self.jsvm.Run(string(code))
_, err = self.jsvm.Run(natspecJS)
if err != nil {
return
}
......@@ -27,39 +24,40 @@ func NewNATSpec(transaction string) (self *NatSpec, err error) {
return
}
self.jsvm.Run("var transaction = " + transaction + ";")
return
}
func (self *NatSpec) SetDescription(desc string) (err error) {
_, err = self.jsvm.Run("var expression = \"" + desc + "\";")
return
}
func (self *NatSpec) SetABI(abi string) (err error) {
_, err = self.jsvm.Run("var abi = " + abi + ";")
return
}
func (self *NatSpec) SetMethod(method string) (err error) {
func (self *NatSpec) Notice(transaction, abi, method, expression string) (string, error) {
var err error
if _, err = self.jsvm.Run("var transaction = " + transaction + ";"); err != nil {
return "", fmt.Errorf("natspec.js error setting transaction: %v", err)
}
_, err = self.jsvm.Run("var method = '" + method + "';")
return
if _, err = self.jsvm.Run("var abi = " + abi + ";"); err != nil {
return "", fmt.Errorf("natspec.js error setting abi: %v", err)
}
}
if _, err = self.jsvm.Run("var method = '" + method + "';"); err != nil {
return "", fmt.Errorf("natspec.js error setting method: %v", err)
}
func (self *NatSpec) Parse() string {
if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil {
return "", fmt.Errorf("natspec.js error setting expression: %v", err)
}
self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
if err != nil {
return err.Error()
return "", fmt.Errorf("natspec.js error evaluating expression: %v", err)
}
evalError := "Natspec evaluation failed, wrong input params"
if value.String() == evalError {
return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression)
}
return value.String()
if len(value.String()) == 0 {
return "", fmt.Errorf("natspec.js error evaluating expression")
}
return value.String(), nil
}
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
package natspec
const natspecJS = `require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
},{}],2:[function(require,module,exports){
// shim for using process in browser
......@@ -3452,8 +3454,8 @@ var natspec = (function () {
var mapExpressionsToEvaluate = function (expression, cb) {
var evaluatedExpression = "";
// match everything in `` quotes
var pattern = /\`(?:\\.|[^`\\])*\`/gim
// match everything in backtick
var pattern = /\` + "`" + `(?:\\.|[^` + "`" + `\\])*\` + "`" + `/gim
var match;
var lastIndex = 0;
while ((match = pattern.exec(expression)) !== null) {
......@@ -3515,3 +3517,4 @@ module.exports = natspec;
},{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]);
`
......@@ -6,7 +6,7 @@ import (
func TestNotice(t *testing.T) {
ns, err := NewNATSpec(`
tx := `
{
"jsonrpc": "2.0",
"method": "eth_call",
......@@ -16,13 +16,9 @@ func TestNotice(t *testing.T) {
}],
"id": 6
}
`)
`
if err != nil {
t.Errorf("NewNATSpec error %v", err)
}
ns.SetABI(`
abi := `
[{
"name": "multiply",
"constant": false,
......@@ -36,11 +32,22 @@ func TestNotice(t *testing.T) {
"type": "uint256"
}]
}]
`)
ns.SetDescription("Will multiply `a` by 7 and return `a * 7`.")
ns.SetMethod("multiply")
`
notice := ns.Parse()
desc := "Will multiply `a` by 7 and return `a * 7`."
method := "multiply"
ns, err := New()
if err != nil {
t.Errorf("NewNATSpec error %v", err)
}
notice, err := ns.Notice(tx, abi, method, desc)
if err != nil {
t.Errorf("expected no error got %v", err)
}
expected := "Will multiply 122 by 7 and return 854."
if notice != expected {
......@@ -48,4 +55,43 @@ func TestNotice(t *testing.T) {
} else {
t.Logf("returned notice \"%v\"", notice)
}
notice, err = ns.Notice(tx, abi, method, "Will multiply 122 by \"7\" and return 854.")
expected = "natspec.js error setting expression: (anonymous): Line 1:41 Unexpected number"
if err == nil {
t.Errorf("expected error, got nothing (notice: '%v')", err, notice)
} else {
if err.Error() != expected {
t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
}
}
// https://github.com/ethereum/natspec.js/issues/1
// badDesc := "Will multiply `e` by 7 and return `a * 7`."
// notice, err = ns.Notice(tx, abi, method, badDesc)
// expected = "natspec.js error evaluating expression: wrong input param in expression ''"
// if err == nil {
// t.Errorf("expected error, got nothing (notice: '%v')", notice)
// } else {
// if err.Error() != expected {
// t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
// }
// }
notice, err = ns.Notice(tx, abi, "missing_method", desc)
expected = "natspec.js error evaluating expression: wrong input params in expression 'Will multiply `a` by 7 and return `a * 7`.'"
if err == nil {
t.Errorf("expected error, got nothing (notice: '%v')", notice)
} else {
if err.Error() != expected {
t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
}
}
}
......@@ -80,13 +80,6 @@ func RunVmTest(p string, t *testing.T) {
helper.CreateFileTests(t, p, &tests)
for name, test := range tests {
/*
vm.Debug = true
helper.Logger.SetLogLevel(4)
if name != "refund_CallToSuicideTwice" {
continue
}
*/
db, _ := ethdb.NewMemDatabase()
statedb := state.New(nil, db)
for addr, account := range test.Pre {
......
......@@ -58,7 +58,7 @@ func (c *Context) GetRangeValue(x, size uint64) []byte {
x = uint64(math.Min(float64(x), float64(len(c.Code))))
y := uint64(math.Min(float64(x+size), float64(len(c.Code))))
return ethutil.LeftPadBytes(c.Code[x:y], int(size))
return ethutil.RightPadBytes(c.Code[x:y], int(size))
}
func (c *Context) GetCode(x, size uint64) []byte {
......
package vm
import "github.com/ethereum/go-ethereum/state"
type Debugger interface {
BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool
StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool
BreakPoints() []int64
SetCode(byteCode []byte)
}
package vm
import "math/big"
type req struct {
stack int
gas *big.Int
}
var _baseCheck = map[OpCode]req{
// Req stack Gas price
ADD: {2, GasFastestStep},
LT: {2, GasFastestStep},
GT: {2, GasFastestStep},
SLT: {2, GasFastestStep},
SGT: {2, GasFastestStep},
EQ: {2, GasFastestStep},
ISZERO: {1, GasFastestStep},
SUB: {2, GasFastestStep},
AND: {2, GasFastestStep},
OR: {2, GasFastestStep},
XOR: {2, GasFastestStep},
NOT: {1, GasFastestStep},
BYTE: {2, GasFastestStep},
CALLDATALOAD: {1, GasFastestStep},
CALLDATACOPY: {3, GasFastestStep},
MLOAD: {1, GasFastestStep},
MSTORE: {2, GasFastestStep},
MSTORE8: {2, GasFastestStep},
CODECOPY: {3, GasFastestStep},
MUL: {2, GasFastStep},
DIV: {2, GasFastStep},
SDIV: {2, GasFastStep},
MOD: {2, GasFastStep},
SMOD: {2, GasFastStep},
SIGNEXTEND: {2, GasFastStep},
ADDMOD: {3, GasMidStep},
MULMOD: {3, GasMidStep},
JUMP: {1, GasMidStep},
JUMPI: {2, GasSlowStep},
EXP: {2, GasSlowStep},
ADDRESS: {0, GasQuickStep},
ORIGIN: {0, GasQuickStep},
CALLER: {0, GasQuickStep},
CALLVALUE: {0, GasQuickStep},
CODESIZE: {0, GasQuickStep},
GASPRICE: {0, GasQuickStep},
COINBASE: {0, GasQuickStep},
TIMESTAMP: {0, GasQuickStep},
NUMBER: {0, GasQuickStep},
CALLDATASIZE: {0, GasQuickStep},
DIFFICULTY: {0, GasQuickStep},
GASLIMIT: {0, GasQuickStep},
POP: {0, GasQuickStep},
PC: {0, GasQuickStep},
MSIZE: {0, GasQuickStep},
GAS: {0, GasQuickStep},
BLOCKHASH: {1, GasExtStep},
BALANCE: {0, GasExtStep},
EXTCODESIZE: {1, GasExtStep},
EXTCODECOPY: {4, GasExtStep},
SLOAD: {1, GasStorageGet},
SSTORE: {2, Zero},
SHA3: {1, GasSha3Base},
CREATE: {3, GasCreate},
CALL: {7, GasCall},
CALLCODE: {7, GasCall},
JUMPDEST: {0, GasJumpDest},
SUICIDE: {1, Zero},
RETURN: {2, Zero},
}
func baseCheck(op OpCode, stack *stack, gas *big.Int) {
if r, ok := _baseCheck[op]; ok {
stack.require(r.stack)
gas.Add(gas, r.gas)
}
}
func toWordSize(size *big.Int) *big.Int {
tmp := new(big.Int)
tmp.Add(size, u256(31))
tmp.Div(tmp, u256(32))
return tmp
}
package vm
import "fmt"
type Memory struct {
store []byte
}
func NewMemory() *Memory {
return &Memory{nil}
}
func (m *Memory) Set(offset, size uint64, value []byte) {
if len(value) > 0 {
totSize := offset + size
lenSize := uint64(len(m.store) - 1)
if totSize > lenSize {
// Calculate the diff between the sizes
diff := totSize - lenSize
if diff > 0 {
// Create a new empty slice and append it
newSlice := make([]byte, diff-1)
// Resize slice
m.store = append(m.store, newSlice...)
}
}
copy(m.store[offset:offset+size], value)
}
}
func (m *Memory) Resize(size uint64) {
if uint64(m.Len()) < size {
m.store = append(m.store, make([]byte, size-uint64(m.Len()))...)
}
}
func (self *Memory) Get(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
}
if len(self.store) > int(offset) {
cpy = make([]byte, size)
copy(cpy, self.store[offset:offset+size])
return
}
return
}
func (m *Memory) Len() int {
return len(m.store)
}
func (m *Memory) Data() []byte {
return m.store
}
func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.store))
if len(m.store) > 0 {
addr := 0
for i := 0; i+32 <= len(m.store); i += 32 {
fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])
addr++
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("####################")
}
......@@ -5,98 +5,53 @@ import (
"math/big"
)
type OpType int
const (
tNorm = iota
tData
tExtro
tCrypto
)
type TxCallback func(opType OpType) bool
// Simple push/pop stack mechanism
type Stack struct {
data []*big.Int
}
func NewStack() *Stack {
return &Stack{}
}
func (st *Stack) Data() []*big.Int {
return st.data
}
func (st *Stack) Len() int {
return len(st.data)
}
func (st *Stack) Pop() *big.Int {
str := st.data[len(st.data)-1]
copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1])
st.data = st.data[:len(st.data)-1]
return str
func newStack() *stack {
return &stack{}
}
func (st *Stack) Popn() (*big.Int, *big.Int) {
ints := st.data[len(st.data)-2:]
copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2])
st.data = st.data[:len(st.data)-2]
return ints[0], ints[1]
type stack struct {
data []*big.Int
ptr int
}
func (st *Stack) Peek() *big.Int {
str := st.data[len(st.data)-1]
return str
func (st *stack) push(d *big.Int) {
if len(st.data) > st.ptr {
st.data[st.ptr] = d
} else {
st.data = append(st.data, d)
}
st.ptr++
}
func (st *Stack) Peekn() (*big.Int, *big.Int) {
ints := st.data[len(st.data)-2:]
return ints[0], ints[1]
func (st *stack) pop() (ret *big.Int) {
st.ptr--
ret = st.data[st.ptr]
return
}
func (st *Stack) Swapn(n int) (*big.Int, *big.Int) {
st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n]
return st.data[len(st.data)-n], st.data[len(st.data)-1]
func (st *stack) len() int {
return st.ptr
}
func (st *Stack) Dupn(n int) *big.Int {
st.Push(st.data[len(st.data)-n])
return st.Peek()
func (st *stack) swap(n int) {
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
}
func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, new(big.Int).Set(d))
func (st *stack) dup(n int) {
st.push(st.data[st.len()-n])
}
func (st *Stack) Get(amount *big.Int) []*big.Int {
// offset + size <= len(data)
length := big.NewInt(int64(len(st.data)))
if amount.Cmp(length) <= 0 {
start := new(big.Int).Sub(length, amount)
return st.data[start.Int64():length.Int64()]
}
return nil
func (st *stack) peek() *big.Int {
return st.data[st.len()-1]
}
func (st *Stack) require(n int) {
if st.Len() < n {
panic(fmt.Sprintf("stack underflow (%d <=> %d)", st.Len(), n))
func (st *stack) require(n int) {
if st.len() < n {
panic(fmt.Sprintf("stack underflow (%d <=> %d)", len(st.data), n))
}
}
func (st *Stack) Print() {
func (st *stack) Print() {
fmt.Println("### stack ###")
if len(st.data) > 0 {
for i, val := range st.data {
......@@ -107,72 +62,3 @@ func (st *Stack) Print() {
}
fmt.Println("#############")
}
type Memory struct {
store []byte
}
func NewMemory() *Memory {
return &Memory{nil}
}
func (m *Memory) Set(offset, size uint64, value []byte) {
if len(value) > 0 {
totSize := offset + size
lenSize := uint64(len(m.store) - 1)
if totSize > lenSize {
// Calculate the diff between the sizes
diff := totSize - lenSize
if diff > 0 {
// Create a new empty slice and append it
newSlice := make([]byte, diff-1)
// Resize slice
m.store = append(m.store, newSlice...)
}
}
copy(m.store[offset:offset+size], value)
}
}
func (m *Memory) Resize(size uint64) {
if uint64(m.Len()) < size {
m.store = append(m.store, make([]byte, size-uint64(m.Len()))...)
}
}
func (self *Memory) Get(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
}
if len(self.store) > int(offset) {
cpy = make([]byte, size)
copy(cpy, self.store[offset:offset+size])
return
}
return
}
func (m *Memory) Len() int {
return len(m.store)
}
func (m *Memory) Data() []byte {
return m.store
}
func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.store))
if len(m.store) > 0 {
addr := 0
for i := 0; i+32 <= len(m.store); i += 32 {
fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])
addr++
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("####################")
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment