mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
Merge remote-tracking branch 'origin/contractinfo' into bzz
Conflicts: eth/backend.go
This commit is contained in:
commit
12d3bc019e
49 changed files with 12521 additions and 973 deletions
|
|
@ -48,18 +48,23 @@ func (self *hive) start(address kademlia.Address, connectPeer func(string) error
|
|||
err = nil
|
||||
}
|
||||
go func() {
|
||||
// whenever pinged ask kademlia about most preferred peer
|
||||
for _ = range self.ping {
|
||||
node, full := self.kad.GetNodeRecord()
|
||||
if node != nil {
|
||||
// if Url known, connect to peer
|
||||
if len(node.Url) > 0 {
|
||||
dpaLogger.Debugf("hive: attempt to connect kaddb node %v", node)
|
||||
connectPeer(node.Url)
|
||||
} else if !full {
|
||||
// a random peer is taken
|
||||
// a random peer is taken from the table
|
||||
peers := self.kad.GetNodes(kademlia.RandomAddress(), 1)
|
||||
if len(peers) > 0 {
|
||||
// a random address at prox bin 0 is sent for lookup
|
||||
req := &retrieveRequestMsgData{
|
||||
Key: Key(common.Hash(kademlia.RandomAddressAt(self.addr, 0)).Bytes()),
|
||||
}
|
||||
dpaLogger.Debugf("hive: look up random address with prox order 0 from peer %v", peers[0])
|
||||
peers[0].(peer).retrieve(req)
|
||||
}
|
||||
}
|
||||
|
|
@ -70,6 +75,7 @@ func (self *hive) start(address kademlia.Address, connectPeer func(string) error
|
|||
}
|
||||
|
||||
func (self *hive) stop() error {
|
||||
// closing ping channel quits the updateloop
|
||||
close(self.ping)
|
||||
return self.kad.Stop(self.path)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -35,6 +36,7 @@ func (js *jsre) adminBindings() {
|
|||
eth := ethO.Object()
|
||||
eth.Set("pendingTransactions", js.pendingTransactions)
|
||||
eth.Set("resend", js.resend)
|
||||
eth.Set("sign", js.sign)
|
||||
|
||||
js.re.Set("admin", struct{}{})
|
||||
t, _ := js.re.Get("admin")
|
||||
|
|
@ -72,6 +74,9 @@ func (js *jsre) adminBindings() {
|
|||
miner.Set("hashrate", js.hashrate)
|
||||
miner.Set("setExtra", js.setExtra)
|
||||
miner.Set("setGasPrice", js.setGasPrice)
|
||||
miner.Set("startAutoDAG", js.startAutoDAG)
|
||||
miner.Set("stopAutoDAG", js.stopAutoDAG)
|
||||
miner.Set("makeDAG", js.makeDAG)
|
||||
|
||||
admin.Set("debug", struct{}{})
|
||||
t, _ = admin.Get("debug")
|
||||
|
|
@ -177,6 +182,30 @@ func (js *jsre) resend(call otto.FunctionCall) otto.Value {
|
|||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
func (js *jsre) sign(call otto.FunctionCall) otto.Value {
|
||||
if len(call.ArgumentList) != 2 {
|
||||
fmt.Println("requires 2 arguments: eth.sign(signer, data)")
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
signer, err := call.Argument(0).ToString()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
|
||||
data, err := call.Argument(1).ToString()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
v, err := js.xeth.Sign(signer, data, false)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
return js.re.ToVal(v)
|
||||
}
|
||||
|
||||
func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
|
||||
block, err := js.getBlock(call)
|
||||
if err != nil {
|
||||
|
|
@ -253,6 +282,30 @@ func (js *jsre) hashrate(otto.FunctionCall) otto.Value {
|
|||
return js.re.ToVal(js.ethereum.Miner().HashRate())
|
||||
}
|
||||
|
||||
func (js *jsre) makeDAG(call otto.FunctionCall) otto.Value {
|
||||
blockNumber, err := call.Argument(1).ToInteger()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
||||
err = ethash.MakeDAG(uint64(blockNumber), "")
|
||||
if err != nil {
|
||||
return otto.FalseValue()
|
||||
}
|
||||
return otto.TrueValue()
|
||||
}
|
||||
|
||||
func (js *jsre) startAutoDAG(otto.FunctionCall) otto.Value {
|
||||
js.ethereum.StartAutoDAG()
|
||||
return otto.TrueValue()
|
||||
}
|
||||
|
||||
func (js *jsre) stopAutoDAG(otto.FunctionCall) otto.Value {
|
||||
js.ethereum.StopAutoDAG()
|
||||
return otto.TrueValue()
|
||||
}
|
||||
|
||||
func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
|
||||
tracestr, err := call.Argument(0).ToString()
|
||||
if err != nil {
|
||||
|
|
@ -291,6 +344,9 @@ func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
|
|||
threads = int64(js.ethereum.MinerThreads)
|
||||
}
|
||||
|
||||
// switch on DAG autogeneration when miner starts
|
||||
js.ethereum.StartAutoDAG()
|
||||
|
||||
err = js.ethereum.StartMining(int(threads))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
|
@ -302,6 +358,7 @@ func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
|
|||
|
||||
func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
|
||||
js.ethereum.StopMining()
|
||||
js.ethereum.StopAutoDAG()
|
||||
return otto.TrueValue()
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +440,7 @@ func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
|
|||
var passphrase string
|
||||
if arg.IsUndefined() {
|
||||
fmt.Println("Please enter a passphrase now.")
|
||||
passphrase, err = readPassword("Passphrase: ", true)
|
||||
passphrase, err = utils.PromptPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
|
|
@ -410,12 +467,12 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
|
|||
if arg.IsUndefined() {
|
||||
fmt.Println("The new account will be encrypted with a passphrase.")
|
||||
fmt.Println("Please enter a passphrase now.")
|
||||
auth, err := readPassword("Passphrase: ", true)
|
||||
auth, err := utils.PromptPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
}
|
||||
confirm, err := readPassword("Repeat Passphrase: ", false)
|
||||
confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
|
|
@ -724,22 +781,22 @@ func (js *jsre) newRegistry(call otto.FunctionCall) otto.Value {
|
|||
|
||||
if len(call.ArgumentList) != 1 {
|
||||
fmt.Println("requires 1 argument: admin.contractInfo.newRegistry(adminaddress)")
|
||||
return otto.FalseValue()
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
addr, err := call.Argument(0).ToString()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
|
||||
var hashReg, urlHint string
|
||||
registry := resolver.New(js.xeth)
|
||||
err = registry.CreateContracts(common.HexToAddress(addr))
|
||||
hashReg, urlHint, err = registry.CreateContracts(common.HexToAddress(addr))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return otto.FalseValue()
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
|
||||
return otto.TrueValue()
|
||||
return js.re.ToVal([]string{hashReg, urlHint})
|
||||
}
|
||||
|
||||
// internal transaction type which will allow us to resend transactions using `eth.resend`
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package main
|
||||
|
||||
var (
|
||||
globalRegistrar = `var GlobalRegistrar = web3.eth.contract([{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}]);`
|
||||
globalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
||||
)
|
||||
|
|
@ -1 +1 @@
|
|||
{"code":"605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056","info":{"abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"compilerVersion":"0.9.17","developerDoc":{"methods":{}},"language":"Solidity","languageVersion":"0","source":"contract test {\n /// @notice Will multiply `a` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply `a` by 7."}}}}}
|
||||
{"code":"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056","info":{"abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"compilerVersion":"0.9.23","developerDoc":{"methods":{}},"language":"Solidity","languageVersion":"0","source":"contract test {\n /// @notice Will multiply `a` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply `a` by 7."}}}}}
|
||||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/docserver"
|
||||
"github.com/ethereum/go-ethereum/common/natspec"
|
||||
"github.com/ethereum/go-ethereum/common/resolver"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
re "github.com/ethereum/go-ethereum/jsre"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
|
@ -71,7 +72,7 @@ type jsre struct {
|
|||
prompter
|
||||
}
|
||||
|
||||
func newJSRE(ethereum *eth.Ethereum, libPath, solcPath, corsDomain string, interactive bool, f xeth.Frontend) *jsre {
|
||||
func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, interactive bool, f xeth.Frontend) *jsre {
|
||||
js := &jsre{ethereum: ethereum, ps1: "> "}
|
||||
// set default cors domain used by startRpc from CLI flag
|
||||
js.corsDomain = corsDomain
|
||||
|
|
@ -81,7 +82,6 @@ func newJSRE(ethereum *eth.Ethereum, libPath, solcPath, corsDomain string, inter
|
|||
js.xeth = xeth.New(ethereum, f)
|
||||
js.wait = js.xeth.UpdateState()
|
||||
// update state in separare forever blocks
|
||||
js.xeth.SetSolc(solcPath)
|
||||
js.re = re.New(libPath)
|
||||
js.apiBindings(f)
|
||||
js.adminBindings()
|
||||
|
|
@ -142,7 +142,7 @@ var net = web3.net;
|
|||
utils.Fatalf("Error setting namespaces: %v", err)
|
||||
}
|
||||
|
||||
js.re.Eval(globalRegistrar + "registrar = new GlobalRegistrar(\"" + globalRegistrarAddr + "\");")
|
||||
js.re.Eval(resolver.GlobalRegistrar + "registrar = GlobalRegistrar.at(\"" + resolver.GlobalRegistrarAddr + "\");")
|
||||
}
|
||||
|
||||
var ds, _ = docserver.New("/")
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
|
||||
const (
|
||||
testSolcPath = ""
|
||||
solcVersion = "0.9.17"
|
||||
solcVersion = "0.9.23"
|
||||
|
||||
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
|
||||
testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||
|
|
@ -34,6 +34,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`))
|
||||
testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}`
|
||||
)
|
||||
|
||||
|
|
@ -75,6 +76,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
|||
AccountManager: am,
|
||||
MaxPeers: 0,
|
||||
Name: "test",
|
||||
SolcPath: testSolcPath,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("%v", err)
|
||||
|
|
@ -101,7 +103,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
|||
t.Errorf("Error creating DocServer: %v", err)
|
||||
}
|
||||
tf := &testjethre{ds: ds, stateDb: ethereum.ChainManager().State().Copy()}
|
||||
repl := newJSRE(ethereum, assetPath, testSolcPath, "", false, tf)
|
||||
repl := newJSRE(ethereum, assetPath, "", false, tf)
|
||||
tf.jsre = repl
|
||||
return tmp, tf, ethereum
|
||||
}
|
||||
|
|
@ -172,6 +174,8 @@ func TestBlockChain(t *testing.T) {
|
|||
tmpfile := filepath.Join(extmp, "export.chain")
|
||||
tmpfileq := strconv.Quote(tmpfile)
|
||||
|
||||
ethereum.ChainManager().Reset()
|
||||
|
||||
checkEvalJSON(t, repl, `admin.export(`+tmpfileq+`)`, `true`)
|
||||
if _, err := os.Stat(tmpfile); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -226,11 +230,11 @@ func TestSignature(t *testing.T) {
|
|||
defer ethereum.Stop()
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
val, err := repl.re.Run(`eth.sign({from: "` + testAddress + `", data: "` + testHash + `"})`)
|
||||
val, err := repl.re.Run(`eth.sign("` + testAddress + `", "` + testHash + `")`)
|
||||
|
||||
// This is a very preliminary test, lacking actual signature verification
|
||||
if err != nil {
|
||||
t.Errorf("Error runnig js: %v", err)
|
||||
t.Errorf("Error running js: %v", err)
|
||||
return
|
||||
}
|
||||
output := val.String()
|
||||
|
|
@ -244,7 +248,6 @@ func TestSignature(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestContract(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
tmp, repl, ethereum := testJEthRE(t)
|
||||
if err := ethereum.Start(); err != nil {
|
||||
|
|
@ -257,7 +260,9 @@ func TestContract(t *testing.T) {
|
|||
var txc uint64
|
||||
coinbase := common.HexToAddress(testAddress)
|
||||
resolver.New(repl.xeth).CreateContracts(coinbase)
|
||||
// time.Sleep(1000 * time.Millisecond)
|
||||
|
||||
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `2`)
|
||||
source := `contract test {\n` +
|
||||
" /// @notice Will multiply `a` by 7." + `\n` +
|
||||
` function multiply(uint a) returns(uint d) {\n` +
|
||||
|
|
@ -277,10 +282,9 @@ func TestContract(t *testing.T) {
|
|||
// if solc is found with right version, test it, otherwise read from file
|
||||
sol, err := compiler.New("")
|
||||
if err != nil {
|
||||
t.Logf("solc not found: skipping compiler test")
|
||||
t.Logf("solc not found: mocking contract compilation step")
|
||||
} else if sol.Version() != solcVersion {
|
||||
err = fmt.Errorf("solc wrong version found (%v, expect %v): skipping compiler test", sol.Version(), solcVersion)
|
||||
t.Log(err)
|
||||
t.Logf("WARNING: solc different version found (%v, test written for %v, may need to update)", sol.Version(), solcVersion)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -293,28 +297,29 @@ func TestContract(t *testing.T) {
|
|||
t.Errorf("%v", err)
|
||||
}
|
||||
} else {
|
||||
checkEvalJSON(t, repl, `contract = eth.compile.solidity(source)`, string(contractInfo))
|
||||
checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo))
|
||||
}
|
||||
|
||||
checkEvalJSON(t, repl, `contract.code`, `"605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056"`)
|
||||
checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`)
|
||||
|
||||
checkEvalJSON(
|
||||
t, repl,
|
||||
`contractaddress = eth.sendTransaction({from: primary, data: contract.code })`,
|
||||
`"0x5dcaace5982778b409c524873b319667eba5d074"`,
|
||||
`"0x291293d57e0a0ab47effe97c02577f90d9211567"`,
|
||||
)
|
||||
|
||||
callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
|
||||
Multiply7 = eth.contract(abiDef);
|
||||
multiply7 = new Multiply7(contractaddress);
|
||||
multiply7 = Multiply7.at(contractaddress);
|
||||
`
|
||||
|
||||
// time.Sleep(1500 * time.Millisecond)
|
||||
_, err = repl.re.Run(callSetup)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error registering, got %v", err)
|
||||
t.Errorf("unexpected error setting up contract, got %v", err)
|
||||
}
|
||||
|
||||
// updatespec
|
||||
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `3`)
|
||||
|
||||
// why is this sometimes failing?
|
||||
// checkEvalJSON(t, repl, `multiply7.multiply.call(6)`, `42`)
|
||||
expNotice := ""
|
||||
|
|
@ -322,20 +327,23 @@ multiply7 = new Multiply7(contractaddress);
|
|||
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
||||
}
|
||||
|
||||
// why 0?
|
||||
checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `0`)
|
||||
|
||||
txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
|
||||
|
||||
checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
|
||||
checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
|
||||
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x4a6c99e127191d2ee302e42182c338344b39a37a47cdbb17ab0f26b6802eb4d1'): {"params":[{"to":"0x5dcaace5982778b409c524873b319667eba5d074","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
|
||||
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x87e2802265838c7f14bb69eecd2112911af6767907a702eeaa445239fb20711b'): {"params":[{"to":"0x291293d57e0a0ab47effe97c02577f90d9211567","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
|
||||
if repl.lastConfirm != expNotice {
|
||||
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
|
||||
}
|
||||
|
||||
var contenthash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"`
|
||||
if sol != nil {
|
||||
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`))
|
||||
_ = modContractInfo
|
||||
// contenthash = crypto.Sha3(modContractInfo)
|
||||
}
|
||||
checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`)
|
||||
checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, `"0x0d067e2dd99a4d8f0c0279738b17130dd415a89f24a23f0e7cf68c546ae3089d"`)
|
||||
checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, contenthash)
|
||||
checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename)`, `true`)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error registering, got %v", err)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -44,13 +43,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/peterh/liner"
|
||||
)
|
||||
import _ "net/http/pprof"
|
||||
|
||||
const (
|
||||
ClientIdentifier = "Geth"
|
||||
Version = "0.9.21.1"
|
||||
Version = "0.9.23"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -101,7 +99,15 @@ The output of this command is supposed to be machine-readable.
|
|||
Usage: "import ethereum presale wallet",
|
||||
},
|
||||
},
|
||||
},
|
||||
Description: `
|
||||
|
||||
get wallet import /path/to/my/presale.wallet
|
||||
|
||||
will prompt for your password and imports your ether presale account.
|
||||
It can be used non-interactively with the --password option taking a
|
||||
passwordfile as argument containing the wallet password in plaintext.
|
||||
|
||||
`},
|
||||
{
|
||||
Action: accountList,
|
||||
Name: "account",
|
||||
|
|
@ -111,7 +117,7 @@ The output of this command is supposed to be machine-readable.
|
|||
Manage accounts lets you create new accounts, list all existing accounts,
|
||||
import a private key into a new account.
|
||||
|
||||
'account help' shows a list of subcommands or help for one subcommand.
|
||||
' help' shows a list of subcommands or help for one subcommand.
|
||||
|
||||
It supports interactive mode, when you are prompted for password as well as
|
||||
non-interactive mode where passwords are supplied via a given password file.
|
||||
|
|
@ -230,6 +236,11 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
|||
Name: "upgradedb",
|
||||
Usage: "upgrade chainblock database",
|
||||
},
|
||||
{
|
||||
Action: removeDb,
|
||||
Name: "removedb",
|
||||
Usage: "Remove blockchain and state databases",
|
||||
},
|
||||
}
|
||||
app.Flags = []cli.Flag{
|
||||
utils.IdentityFlag,
|
||||
|
|
@ -246,6 +257,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
|||
utils.GasPriceFlag,
|
||||
utils.MinerThreadsFlag,
|
||||
utils.MiningEnabledFlag,
|
||||
utils.AutoDAGFlag,
|
||||
utils.NATFlag,
|
||||
utils.NatspecEnabledFlag,
|
||||
utils.NodeKeyFileFlag,
|
||||
|
|
@ -324,7 +336,6 @@ func console(ctx *cli.Context) {
|
|||
repl := newJSRE(
|
||||
ethereum,
|
||||
ctx.String(utils.JSpathFlag.Name),
|
||||
ctx.String(utils.SolcPathFlag.Name),
|
||||
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
||||
true,
|
||||
nil,
|
||||
|
|
@ -346,7 +357,6 @@ func execJSFiles(ctx *cli.Context) {
|
|||
repl := newJSRE(
|
||||
ethereum,
|
||||
ctx.String(utils.JSpathFlag.Name),
|
||||
ctx.String(utils.SolcPathFlag.Name),
|
||||
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
||||
false,
|
||||
nil,
|
||||
|
|
@ -362,12 +372,20 @@ func execJSFiles(ctx *cli.Context) {
|
|||
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
|
||||
var err error
|
||||
// Load startup keys. XXX we are going to need a different format
|
||||
// Attempt to unlock the account
|
||||
passphrase = getPassPhrase(ctx, "", false)
|
||||
|
||||
if len(account) == 0 {
|
||||
utils.Fatalf("Invalid account address '%s'", account)
|
||||
}
|
||||
// Attempt to unlock the account 3 times
|
||||
attempts := 3
|
||||
for tries := 0; tries < attempts; tries++ {
|
||||
msg := fmt.Sprintf("Unlocking account %s...%s | Attempt %d/%d", account[:8], account[len(account)-6:], tries+1, attempts)
|
||||
passphrase = getPassPhrase(ctx, msg, false)
|
||||
err = am.Unlock(common.HexToAddress(account), passphrase)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
utils.Fatalf("Unlock account failed '%v'", err)
|
||||
}
|
||||
|
|
@ -382,6 +400,8 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|||
am := eth.AccountManager()
|
||||
|
||||
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||
accounts := strings.Split(account, " ")
|
||||
for _, account := range accounts {
|
||||
if len(account) > 0 {
|
||||
if account == "primary" {
|
||||
primaryAcc, err := am.Primary()
|
||||
|
|
@ -392,6 +412,7 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|||
}
|
||||
unlockAccount(ctx, am, account)
|
||||
}
|
||||
}
|
||||
// Start auxiliary services if enabled.
|
||||
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
||||
if err := utils.StartRPC(eth, ctx); err != nil {
|
||||
|
|
@ -422,12 +443,12 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
|
|||
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
||||
if len(passfile) == 0 {
|
||||
fmt.Println(desc)
|
||||
auth, err := readPassword("Passphrase: ", true)
|
||||
auth, err := utils.PromptPassword("Passphrase: ", true)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
}
|
||||
if confirmation {
|
||||
confirm, err := readPassword("Repeat Passphrase: ", false)
|
||||
confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
|
||||
if err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
}
|
||||
|
|
@ -544,6 +565,25 @@ func exportchain(ctx *cli.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
func removeDb(ctx *cli.Context) {
|
||||
confirm, err := utils.PromptConfirm("Remove local databases?")
|
||||
if err != nil {
|
||||
utils.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if confirm {
|
||||
fmt.Println("Removing chain and state databases...")
|
||||
start := time.Now()
|
||||
|
||||
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
|
||||
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
|
||||
|
||||
fmt.Printf("Removed in %v\n", time.Since(start))
|
||||
} else {
|
||||
fmt.Println("Operation aborted")
|
||||
}
|
||||
}
|
||||
|
||||
func upgradeDb(ctx *cli.Context) {
|
||||
fmt.Println("Upgrade blockchain DB")
|
||||
|
||||
|
|
@ -575,6 +615,7 @@ func upgradeDb(ctx *cli.Context) {
|
|||
ethereum.ExtraDb().Close()
|
||||
|
||||
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
|
||||
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
|
||||
|
||||
ethereum, err = eth.New(cfg)
|
||||
if err != nil {
|
||||
|
|
@ -666,18 +707,3 @@ func hashish(x string) bool {
|
|||
_, err := strconv.Atoi(x)
|
||||
return err != nil
|
||||
}
|
||||
|
||||
func readPassword(prompt string, warnTerm bool) (string, error) {
|
||||
if liner.TerminalSupported() {
|
||||
lr := liner.NewLiner()
|
||||
defer lr.Close()
|
||||
return lr.PasswordPrompt(prompt)
|
||||
}
|
||||
if warnTerm {
|
||||
fmt.Println("!! Unsupported terminal, password will be echoed.")
|
||||
}
|
||||
fmt.Print(prompt)
|
||||
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
fmt.Println()
|
||||
return input, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,13 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -35,6 +37,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/peterh/liner"
|
||||
)
|
||||
|
||||
var interruptCallbacks = []func(os.Signal){}
|
||||
|
|
@ -71,18 +74,45 @@ func openLogFile(Datadir string, filename string) *os.File {
|
|||
return file
|
||||
}
|
||||
|
||||
func confirm(message string) bool {
|
||||
fmt.Println(message, "Are you sure? (y/n)")
|
||||
var r string
|
||||
fmt.Scanln(&r)
|
||||
for ; ; fmt.Scanln(&r) {
|
||||
if r == "n" || r == "y" {
|
||||
break
|
||||
func PromptConfirm(prompt string) (bool, error) {
|
||||
var (
|
||||
input string
|
||||
err error
|
||||
)
|
||||
prompt = prompt + " [y/N] "
|
||||
|
||||
if liner.TerminalSupported() {
|
||||
lr := liner.NewLiner()
|
||||
defer lr.Close()
|
||||
input, err = lr.Prompt(prompt)
|
||||
} else {
|
||||
fmt.Printf("Yes or no? (%s)", r)
|
||||
fmt.Print(prompt)
|
||||
input, err = bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
return r == "y"
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func PromptPassword(prompt string, warnTerm bool) (string, error) {
|
||||
if liner.TerminalSupported() {
|
||||
lr := liner.NewLiner()
|
||||
defer lr.Close()
|
||||
return lr.PasswordPrompt(prompt)
|
||||
}
|
||||
if warnTerm {
|
||||
fmt.Println("!! Unsupported terminal, password will be echoed.")
|
||||
}
|
||||
fmt.Print(prompt)
|
||||
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
fmt.Println()
|
||||
return input, err
|
||||
}
|
||||
|
||||
func initDataDir(Datadir string) {
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ var (
|
|||
Name: "mine",
|
||||
Usage: "Enable mining",
|
||||
}
|
||||
AutoDAGFlag = cli.BoolFlag{
|
||||
Name: "autodag",
|
||||
Usage: "Enable automatic DAG pregeneration",
|
||||
}
|
||||
EtherbaseFlag = cli.StringFlag{
|
||||
Name: "etherbase",
|
||||
Usage: "Public address for block mining rewards. By default the address of your primary account is used",
|
||||
|
|
@ -318,6 +322,8 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
|||
Dial: true,
|
||||
BootNodes: ctx.GlobalString(BootnodesFlag.Name),
|
||||
GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
|
||||
SolcPath: ctx.GlobalString(SolcPathFlag.Name),
|
||||
AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name),
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -341,8 +347,8 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat
|
|||
}
|
||||
|
||||
eventMux := new(event.TypeMux)
|
||||
chainManager := core.NewChainManager(blockDb, stateDb, eventMux)
|
||||
pow := ethash.New()
|
||||
chainManager := core.NewChainManager(blockDb, stateDb, pow, eventMux)
|
||||
txPool := core.NewTxPool(eventMux, chainManager.State, chainManager.GasLimit)
|
||||
blockProcessor := core.NewBlockProcessor(stateDb, extraDb, pow, txPool, chainManager, eventMux)
|
||||
chainManager.SetProcessor(blockProcessor)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
flair = "Christian <c@ethdev.com> and Lefteris <lefteris@ethdev.com> (c) 2014-2015"
|
||||
// flair = "Christian <c@ethdev.com> and Lefteris <lefteris@ethdev.com> (c) 2014-2015"
|
||||
flair = ""
|
||||
languageVersion = "0"
|
||||
)
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ func (sol *Solidity) Version() string {
|
|||
return sol.version
|
||||
}
|
||||
|
||||
func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
||||
func (sol *Solidity) Compile(source string) (contracts map[string]*Contract, err error) {
|
||||
|
||||
if len(source) == 0 {
|
||||
err = fmt.Errorf("empty source")
|
||||
|
|
@ -122,11 +123,10 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
err = fmt.Errorf("solc error: missing code output")
|
||||
return
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
err = fmt.Errorf("multi-contract sources are not supported")
|
||||
return
|
||||
}
|
||||
_, file := filepath.Split(matches[0])
|
||||
|
||||
contracts = make(map[string]*Contract)
|
||||
for _, path := range matches {
|
||||
_, file := filepath.Split(path)
|
||||
base := strings.Split(file, ".")[0]
|
||||
|
||||
codeFile := filepath.Join(wd, base+".binary")
|
||||
|
|
@ -134,12 +134,13 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
userDocFile := filepath.Join(wd, base+".docuser")
|
||||
developerDocFile := filepath.Join(wd, base+".docdev")
|
||||
|
||||
code, err := ioutil.ReadFile(codeFile)
|
||||
var code, abiDefinitionJson, userDocJson, developerDocJson []byte
|
||||
code, err = ioutil.ReadFile(codeFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error reading compiler output for code: %v", err)
|
||||
return
|
||||
}
|
||||
abiDefinitionJson, err := ioutil.ReadFile(abiDefinitionFile)
|
||||
abiDefinitionJson, err = ioutil.ReadFile(abiDefinitionFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error reading compiler output for abiDefinition: %v", err)
|
||||
return
|
||||
|
|
@ -147,7 +148,7 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
var abiDefinition interface{}
|
||||
err = json.Unmarshal(abiDefinitionJson, &abiDefinition)
|
||||
|
||||
userDocJson, err := ioutil.ReadFile(userDocFile)
|
||||
userDocJson, err = ioutil.ReadFile(userDocFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error reading compiler output for userDoc: %v", err)
|
||||
return
|
||||
|
|
@ -155,7 +156,7 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
var userDoc interface{}
|
||||
err = json.Unmarshal(userDocJson, &userDoc)
|
||||
|
||||
developerDocJson, err := ioutil.ReadFile(developerDocFile)
|
||||
developerDocJson, err = ioutil.ReadFile(developerDocFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error reading compiler output for developerDoc: %v", err)
|
||||
return
|
||||
|
|
@ -163,8 +164,8 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
var developerDoc interface{}
|
||||
err = json.Unmarshal(developerDocJson, &developerDoc)
|
||||
|
||||
contract = &Contract{
|
||||
Code: string(code),
|
||||
contract := &Contract{
|
||||
Code: "0x" + string(code),
|
||||
Info: ContractInfo{
|
||||
Source: source,
|
||||
Language: "Solidity",
|
||||
|
|
@ -176,6 +177,9 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) {
|
|||
},
|
||||
}
|
||||
|
||||
contracts[base] = contract
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const solcVersion = "0.9.17"
|
||||
const solcVersion = "0.9.23"
|
||||
|
||||
var (
|
||||
source = `
|
||||
|
|
@ -20,37 +20,45 @@ contract test {
|
|||
}
|
||||
}
|
||||
`
|
||||
code = "605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056"
|
||||
info = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0","compilerVersion":"0.9.17","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}`
|
||||
code = "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"
|
||||
info = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0","compilerVersion":"0.9.23","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}`
|
||||
|
||||
infohash = common.HexToHash("0x834075768a68e500e459b9c3213750c84de3df47156500cb01bb664d3f88c60a")
|
||||
infohash = common.HexToHash("0xea782f674eb898e477c20e8a7cf11c2c28b09fa68b5278732104f7a101aed255")
|
||||
)
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
sol, err := New("")
|
||||
if err != nil {
|
||||
t.Skip("no solc installed")
|
||||
t.Skip("solc not found: skip")
|
||||
} else if sol.Version() != solcVersion {
|
||||
t.Logf("WARNING: a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion)
|
||||
}
|
||||
contract, err := sol.Compile(source)
|
||||
contracts, err := sol.Compile(source)
|
||||
if err != nil {
|
||||
t.Errorf("error compiling source. result %v: %v", contract, err)
|
||||
t.Errorf("error compiling source. result %v: %v", contracts, err)
|
||||
return
|
||||
}
|
||||
/*
|
||||
if contract.Code != code {
|
||||
t.Errorf("wrong code, expected\n%s, got\n%s", code, contract.Code)
|
||||
|
||||
if len(contracts) != 1 {
|
||||
t.Errorf("one contract expected, got\n%s", len(contracts))
|
||||
}
|
||||
*/
|
||||
|
||||
if contracts["test"].Code != code {
|
||||
t.Errorf("wrong code, expected\n%s, got\n%s", code, contracts["test"].Code)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCompileError(t *testing.T) {
|
||||
sol, err := New("")
|
||||
if err != nil || sol.version != solcVersion {
|
||||
t.Skip("no solc installed")
|
||||
t.Skip("solc not found: skip")
|
||||
} else if sol.Version() != solcVersion {
|
||||
t.Logf("WARNING: a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion)
|
||||
}
|
||||
contract, err := sol.Compile(source[2:])
|
||||
contracts, err := sol.Compile(source[2:])
|
||||
if err == nil {
|
||||
t.Errorf("error expected compiling source. got none. result %v", contract)
|
||||
t.Errorf("error expected compiling source. got none. result %v", contracts)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -78,11 +86,11 @@ func TestExtractInfo(t *testing.T) {
|
|||
os.Remove(filename)
|
||||
cinfohash, err := ExtractInfo(contract, filename)
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
t.Errorf("error extracting info: %v", err)
|
||||
}
|
||||
got, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
t.Errorf("error reading '%v': %v", filename, err)
|
||||
}
|
||||
if string(got) != info {
|
||||
t.Errorf("incorrect info.json extracted, expected:\n%s\ngot\n%s", info, string(got))
|
||||
|
|
|
|||
|
|
@ -197,8 +197,11 @@ func TestNatspecE2E(t *testing.T) {
|
|||
codehash := common.BytesToHash(crypto.Sha3(codeb))
|
||||
|
||||
// use resolver to register codehash->dochash->url
|
||||
// test if globalregistry works
|
||||
// resolver.HashRefContractAddress = "0x0"
|
||||
// resolver.UrlHintContractAddress = "0x0"
|
||||
registry := resolver.New(tf.xeth)
|
||||
_, err := registry.Register(tf.coinbase, codehash, dochash, "file:///"+testFileName)
|
||||
_, err := registry.RegisterAddrWithUrl(tf.coinbase, codehash, dochash, "file:///"+testFileName)
|
||||
if err != nil {
|
||||
t.Errorf("error registering: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,6 @@ const ( // built-in contracts address and code
|
|||
}
|
||||
*/
|
||||
|
||||
GlobalRegistrar = `var GlobalRegistrar = web3.eth.contract([{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}]);`
|
||||
GlobalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ of a url scheme
|
|||
*/
|
||||
|
||||
// // contract addresses will be hardcoded after they're created
|
||||
var UrlHintContractAddress, HashRegContractAddress string
|
||||
var (
|
||||
UrlHintContractAddress = "0x0"
|
||||
HashRegContractAddress = "0x0"
|
||||
)
|
||||
|
||||
const (
|
||||
txValue = "0"
|
||||
|
|
@ -28,42 +31,167 @@ const (
|
|||
txGasPrice = "1000000000000"
|
||||
)
|
||||
|
||||
func abi(s string) string {
|
||||
func abiSignature(s string) string {
|
||||
return common.ToHex(crypto.Sha3([]byte(s))[:4])
|
||||
}
|
||||
|
||||
var (
|
||||
registerContentHashAbi = abi("register(uint256,uint256)")
|
||||
registerUrlAbi = abi("register(uint256,uint8,uint256)")
|
||||
setOwnerAbi = abi("setowner()")
|
||||
HashReg = "HashReg"
|
||||
UrlHint = "UrlHint"
|
||||
|
||||
registerContentHashAbi = abiSignature("register(uint256,uint256)")
|
||||
registerUrlAbi = abiSignature("register(uint256,uint8,uint256)")
|
||||
setOwnerAbi = abiSignature("setowner()")
|
||||
reserveAbi = abiSignature("reserve(bytes32)")
|
||||
resolveAbi = abiSignature("addr(bytes32)")
|
||||
registerAbi = abiSignature("setAddress(bytes32,address,bool)")
|
||||
addressAbiPrefix = string(make([]byte, 24))
|
||||
)
|
||||
|
||||
type Backend interface {
|
||||
StorageAt(string, string) string
|
||||
Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error)
|
||||
Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error)
|
||||
}
|
||||
|
||||
type Resolver struct {
|
||||
backend Backend
|
||||
}
|
||||
|
||||
func New(eth Backend) *Resolver {
|
||||
return &Resolver{eth}
|
||||
func New(eth Backend) (res *Resolver) {
|
||||
res = &Resolver{eth}
|
||||
res.setContracts()
|
||||
return
|
||||
}
|
||||
|
||||
// for testing and play temporarily
|
||||
// ideally the HashReg and UrlHint contracts should be in the genesis block
|
||||
// if we got build-in support for natspec/contract info
|
||||
// there should be only one of these officially endorsed
|
||||
// addresses as constants
|
||||
// TODO: could get around this with namereg, check
|
||||
func (self *Resolver) CreateContracts(addr common.Address) (err error) {
|
||||
HashRegContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeHashReg)
|
||||
func (self *Resolver) setContracts() {
|
||||
var err error
|
||||
if HashRegContractAddress != "0x0" {
|
||||
return
|
||||
}
|
||||
// reset iff error anywhere
|
||||
defer func() {
|
||||
if err != nil {
|
||||
HashRegContractAddress = "0x0"
|
||||
}
|
||||
}()
|
||||
hashRegAbi := registerAbi + string(common.Hex2BytesFixed(HashRegContractAddress[2:], 32))
|
||||
HashRegContractAddress, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", hashRegAbi)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("HashReg address not found: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if UrlHintContractAddress != "0x0" {
|
||||
return
|
||||
}
|
||||
// reset iff error anywhere
|
||||
defer func() {
|
||||
if err != nil {
|
||||
UrlHintContractAddress = "0x0"
|
||||
}
|
||||
}()
|
||||
|
||||
urlHintAbi := registerAbi + string(common.Hex2BytesFixed(UrlHintContractAddress[2:], 32))
|
||||
UrlHintContractAddress, _, err = self.backend.Call("", GlobalRegistrarAddr, "", "", "", urlHintAbi)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("UrlHint address not found: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
glog.V(logger.Detail).Infof("HashReg @ %v\nUrlHint @ %v\n", HashRegContractAddress, UrlHintContractAddress)
|
||||
}
|
||||
|
||||
// This can be safely called from tests to or private chains to create
|
||||
// new HashReg and UrlHint contracts (requires transaction)
|
||||
// It does nothing if addresses are set
|
||||
func (self *Resolver) CreateContracts(addr common.Address) (hashReg, urlHint string, err error) {
|
||||
if HashRegContractAddress != "0x0" {
|
||||
err = fmt.Errorf("HashReg already exists at %v", HashRegContractAddress)
|
||||
return
|
||||
}
|
||||
hashReg, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeHashReg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
UrlHintContractAddress, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeURLhint)
|
||||
_, err = self.Reserve(addr, HashReg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = self.RegisterAddress(addr, HashReg, common.HexToAddress(hashReg))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if UrlHintContractAddress != "0x0" {
|
||||
err = fmt.Errorf("UrlHint already exists at %v", UrlHintContractAddress)
|
||||
return
|
||||
}
|
||||
urlHint, err = self.backend.Transact(addr.Hex(), "", "", txValue, txGas, txGasPrice, ContractCodeURLhint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = self.Reserve(addr, UrlHint)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = self.RegisterAddress(addr, UrlHint, common.HexToAddress(urlHint))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
HashRegContractAddress = hashReg
|
||||
UrlHintContractAddress = urlHint
|
||||
glog.V(logger.Detail).Infof("HashReg @ %v\nUrlHint @ %v\n", HashRegContractAddress, UrlHintContractAddress)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Reserve(from, name) reserves name for the sender address in the globalRegistrar
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Resolver) Reserve(address common.Address, name string) (txh string, err error) {
|
||||
nameHex, extra := encodeName(name, 6)
|
||||
abi := reserveAbi + nameHex + extra
|
||||
return self.backend.Transact(
|
||||
address.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", txValue, txGas, txGasPrice,
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterAddress(from, name, addr) will set the Address to address for name
|
||||
// in the globalRegistrar using from as the sender of the transaction
|
||||
// the tx needs to be mined to take effect
|
||||
func (self *Resolver) RegisterAddress(from common.Address, name string, address common.Address) (txh string, err error) {
|
||||
nameHex, extra := encodeName(name, 6)
|
||||
addrHex := encodeAddress(address)
|
||||
|
||||
trueHex := make([]byte, 64)
|
||||
trueHex[63] = 1
|
||||
|
||||
abi := registerAbi + nameHex + addrHex + extra
|
||||
return self.backend.Transact(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
"", txValue, txGas, txGasPrice,
|
||||
abi,
|
||||
)
|
||||
}
|
||||
|
||||
// NameToAddr(from, name) queries the registrar for the address on
|
||||
func (self *Resolver) NameToAddr(from common.Address, name string) (address common.Address, err error) {
|
||||
nameHex, extra := encodeName(name, 2)
|
||||
abi := resolveAbi + nameHex + extra
|
||||
res, _, err := self.backend.Call(
|
||||
from.Hex(),
|
||||
GlobalRegistrarAddr,
|
||||
txValue, txGas, txGasPrice,
|
||||
abi,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
address = common.HexToAddress(res)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +266,7 @@ func (self *Resolver) RegisterUrl(address common.Address, hash common.Hash, url
|
|||
return
|
||||
}
|
||||
|
||||
func (self *Resolver) Register(address common.Address, codehash, dochash common.Hash, url string) (txh string, err error) {
|
||||
func (self *Resolver) RegisterAddrWithUrl(address common.Address, codehash, dochash common.Hash, url string) (txh string, err error) {
|
||||
|
||||
_, err = self.RegisterContentHash(address, codehash, dochash)
|
||||
if err != nil {
|
||||
|
|
@ -151,7 +279,7 @@ func (self *Resolver) Register(address common.Address, codehash, dochash common.
|
|||
// implemented as direct retrieval from db
|
||||
func (self *Resolver) KeyToContentHash(khash common.Hash) (chash common.Hash, err error) {
|
||||
// look up in hashReg
|
||||
at := common.Bytes2Hex(common.FromHex(HashRegContractAddress))
|
||||
at := HashRegContractAddress[2:]
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), khash[:]))
|
||||
hash := self.backend.StorageAt(at, key)
|
||||
|
||||
|
|
@ -172,7 +300,7 @@ func (self *Resolver) ContentHashToUrl(chash common.Hash) (uri string, err error
|
|||
for len(str) > 0 {
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), chash[:])
|
||||
key := storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(idx)))
|
||||
hex := self.backend.StorageAt(UrlHintContractAddress, key)
|
||||
hex := self.backend.StorageAt(UrlHintContractAddress[2:], key)
|
||||
str = string(common.Hex2Bytes(hex[2:]))
|
||||
l := len(str)
|
||||
for (l > 0) && (str[l-1] == 0) {
|
||||
|
|
@ -230,3 +358,18 @@ func storageFixedArray(addr, idx []byte) []byte {
|
|||
func storageAddress(addr []byte) string {
|
||||
return common.ToHex(addr)
|
||||
}
|
||||
|
||||
func encodeAddress(address common.Address) string {
|
||||
return addressAbiPrefix + address.Hex()[2:]
|
||||
}
|
||||
|
||||
func encodeName(name string, index uint8) (nameHex, extra string) {
|
||||
nameHexBytes := make([]byte, 64)
|
||||
if len(name) > 32 {
|
||||
nameHexBytes[63] = byte(index)
|
||||
extra = common.Bytes2Hex([]byte(name))
|
||||
} else {
|
||||
copy(nameHexBytes, []byte(name))
|
||||
}
|
||||
return string(nameHexBytes), extra
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,22 +20,22 @@ var (
|
|||
)
|
||||
|
||||
func NewTestBackend() *testBackend {
|
||||
HashRegContractAddress = common.BigToAddress(common.Big0).Hex()[2:]
|
||||
UrlHintContractAddress = common.BigToAddress(common.Big1).Hex()[2:]
|
||||
HashRegContractAddress = common.BigToAddress(common.Big0).Hex() //[2:]
|
||||
UrlHintContractAddress = common.BigToAddress(common.Big1).Hex() //[2:]
|
||||
self := &testBackend{}
|
||||
self.contracts = make(map[string](map[string]string))
|
||||
|
||||
self.contracts[HashRegContractAddress] = make(map[string]string)
|
||||
self.contracts[HashRegContractAddress[2:]] = make(map[string]string)
|
||||
key := storageAddress(storageMapping(storageIdx2Addr(1), codehash[:]))
|
||||
self.contracts[HashRegContractAddress][key] = hash.Hex()
|
||||
self.contracts[HashRegContractAddress[2:]][key] = hash.Hex()
|
||||
|
||||
self.contracts[UrlHintContractAddress] = make(map[string]string)
|
||||
self.contracts[UrlHintContractAddress[2:]] = make(map[string]string)
|
||||
mapaddr := storageMapping(storageIdx2Addr(1), hash[:])
|
||||
|
||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(0)))
|
||||
self.contracts[UrlHintContractAddress][key] = common.ToHex([]byte(url))
|
||||
self.contracts[UrlHintContractAddress[2:]][key] = common.ToHex([]byte(url))
|
||||
key = storageAddress(storageFixedArray(mapaddr, storageIdx2Addr(1)))
|
||||
self.contracts[UrlHintContractAddress][key] = "0x00"
|
||||
self.contracts[UrlHintContractAddress[2:]][key] = "0x0"
|
||||
return self
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +52,20 @@ func (self *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, ga
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func (self *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func TestCreateContractsExists(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
_, _, err := res.CreateContracts(common.BigToAddress(common.Big0))
|
||||
exp := "HashReg already exists at 0x0000000000000000000000000000000000000000"
|
||||
if err == nil || err.Error() != exp {
|
||||
t.Errorf("expected error '%s', got '%v'", exp, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyToContentHash(t *testing.T) {
|
||||
b := NewTestBackend()
|
||||
res := New(b)
|
||||
|
|
@ -71,7 +85,7 @@ func TestContentHashToUrl(t *testing.T) {
|
|||
res := New(b)
|
||||
got, err := res.ContentHashToUrl(hash)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
t.Errorf("expected error, got %v", err)
|
||||
} else {
|
||||
if got != url {
|
||||
t.Errorf("incorrect result, expected '%v', got '%s'", url, got)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ func (bc *BlockCache) Get(hash common.Hash) *types.Block {
|
|||
}
|
||||
|
||||
func (bc *BlockCache) Has(hash common.Hash) bool {
|
||||
bc.mu.RLock()
|
||||
defer bc.mu.RUnlock()
|
||||
|
||||
_, ok := bc.blocks[hash]
|
||||
return ok
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ const (
|
|||
BlockChainVersion = 2
|
||||
)
|
||||
|
||||
var receiptsPre = []byte("receipts-")
|
||||
|
||||
type BlockProcessor struct {
|
||||
db common.Database
|
||||
extraDb common.Database
|
||||
|
|
@ -189,7 +191,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||
state := state.New(parent.Root(), sm.db)
|
||||
|
||||
// Block validation
|
||||
if err = sm.ValidateHeader(block.Header(), parent.Header()); err != nil {
|
||||
if err = sm.ValidateHeader(block.Header(), parent.Header(), false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -263,13 +265,27 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
|
|||
putTx(sm.extraDb, tx, block, uint64(i))
|
||||
}
|
||||
|
||||
receiptsRlp := block.Receipts().RlpEncode()
|
||||
sm.extraDb.Put(append(receiptsPre, block.Hash().Bytes()...), receiptsRlp)
|
||||
|
||||
return state.Logs(), nil
|
||||
}
|
||||
|
||||
func (self *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
|
||||
var rdata []byte
|
||||
rdata, err = self.extraDb.Get(append(receiptsPre, bhash[:]...))
|
||||
|
||||
if err == nil {
|
||||
err = rlp.DecodeBytes(rdata, &receipts)
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Validates the current block. Returns an error if the block was invalid,
|
||||
// an uncle or anything that isn't on the current block chain.
|
||||
// Validation validates easy over difficult (dagger takes longer time = difficult)
|
||||
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
|
||||
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error {
|
||||
if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
|
||||
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
|
||||
}
|
||||
|
|
@ -300,10 +316,12 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header) error {
|
|||
return BlockEqualTSErr //ValidationError("Block timestamp equal or less than previous block (%v - %v)", block.Time, parent.Time)
|
||||
}
|
||||
|
||||
if checkPow {
|
||||
// Verify the nonce of the block. Return an error if it's not valid
|
||||
if !sm.Pow.Verify(types.NewBlockWithHeader(block)) {
|
||||
return ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -351,6 +369,13 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
|
|||
uncles.Add(hash)
|
||||
|
||||
if ancestors.Has(hash) {
|
||||
branch := fmt.Sprintf(" O - %x\n |\n", block.Hash())
|
||||
ancestors.Each(func(item interface{}) bool {
|
||||
branch += fmt.Sprintf(" O - %x\n |\n", hash)
|
||||
return true
|
||||
})
|
||||
glog.Infoln(branch)
|
||||
|
||||
return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +383,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
|
|||
return UncleError("uncle[%d](%x)'s parent unknown (%x)", i, hash[:4], uncle.ParentHash[0:4])
|
||||
}
|
||||
|
||||
if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil {
|
||||
if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash], true); err != nil {
|
||||
return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func proc() (*BlockProcessor, *ChainManager) {
|
|||
db, _ := ethdb.NewMemDatabase()
|
||||
var mux event.TypeMux
|
||||
|
||||
chainMan := NewChainManager(db, db, &mux)
|
||||
chainMan := NewChainManager(db, db, thePow(), &mux)
|
||||
return NewBlockProcessor(db, db, ezp.New(), nil, chainMan, &mux), chainMan
|
||||
}
|
||||
|
||||
|
|
@ -24,13 +24,13 @@ func TestNumber(t *testing.T) {
|
|||
block1.Header().Number = big.NewInt(3)
|
||||
block1.Header().Time--
|
||||
|
||||
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
||||
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header(), false)
|
||||
if err != BlockNumberErr {
|
||||
t.Errorf("expected block number error %v", err)
|
||||
}
|
||||
|
||||
block1 = chain.NewBlock(common.Address{})
|
||||
err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
||||
err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header(), false)
|
||||
if err == BlockNumberErr {
|
||||
t.Errorf("didn't expect block number error")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Dat
|
|||
// Effectively a fork factory
|
||||
func newChainManager(block *types.Block, eventMux *event.TypeMux, db common.Database) *ChainManager {
|
||||
genesis := GenesisBlock(db)
|
||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: eventMux}
|
||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: eventMux, pow: FakePow{}}
|
||||
bc.txState = state.ManageState(state.New(genesis.Root(), db))
|
||||
bc.futureBlocks = NewBlockCache(1000)
|
||||
if block == nil {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -15,6 +16,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -84,6 +86,7 @@ type ChainManager struct {
|
|||
genesisBlock *types.Block
|
||||
// Last known total difficulty
|
||||
mu sync.RWMutex
|
||||
chainmu sync.RWMutex
|
||||
tsmu sync.RWMutex
|
||||
|
||||
td *big.Int
|
||||
|
|
@ -99,9 +102,11 @@ type ChainManager struct {
|
|||
|
||||
quit chan struct{}
|
||||
wg sync.WaitGroup
|
||||
|
||||
pow pow.PoW
|
||||
}
|
||||
|
||||
func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *ChainManager {
|
||||
func NewChainManager(blockDb, stateDb common.Database, pow pow.PoW, mux *event.TypeMux) *ChainManager {
|
||||
bc := &ChainManager{
|
||||
blockDb: blockDb,
|
||||
stateDb: stateDb,
|
||||
|
|
@ -109,6 +114,7 @@ func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *Chai
|
|||
eventMux: mux,
|
||||
quit: make(chan struct{}),
|
||||
cache: NewBlockCache(blockCacheLimit),
|
||||
pow: pow,
|
||||
}
|
||||
bc.setLastState()
|
||||
|
||||
|
|
@ -342,7 +348,7 @@ func (self *ChainManager) Export(w io.Writer) error {
|
|||
|
||||
last := self.currentBlock.NumberU64()
|
||||
|
||||
for nr := uint64(0); nr <= last; nr++ {
|
||||
for nr := uint64(1); nr <= last; nr++ {
|
||||
block := self.GetBlockByNumber(nr)
|
||||
if block == nil {
|
||||
return fmt.Errorf("export failed on #%d: not found", nr)
|
||||
|
|
@ -406,9 +412,11 @@ func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) (
|
|||
}
|
||||
|
||||
func (self *ChainManager) GetBlock(hash common.Hash) *types.Block {
|
||||
/*
|
||||
if block := self.cache.Get(hash); block != nil {
|
||||
return block
|
||||
}
|
||||
*/
|
||||
|
||||
data, _ := self.blockDb.Get(append(blockHashPre, hash[:]...))
|
||||
if len(data) == 0 {
|
||||
|
|
@ -518,6 +526,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
|
|||
self.wg.Add(1)
|
||||
defer self.wg.Done()
|
||||
|
||||
self.chainmu.Lock()
|
||||
defer self.chainmu.Unlock()
|
||||
|
||||
// A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring.
|
||||
var (
|
||||
queue = make([]interface{}, len(chain))
|
||||
|
|
@ -525,10 +536,19 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
|
|||
stats struct{ queued, processed, ignored int }
|
||||
tstart = time.Now()
|
||||
)
|
||||
|
||||
// check the nonce in parallel to the block processing
|
||||
// this speeds catching up significantly
|
||||
nonceErrCh := make(chan error)
|
||||
go func() {
|
||||
nonceErrCh <- verifyNonces(self.pow, chain)
|
||||
}()
|
||||
|
||||
for i, block := range chain {
|
||||
if block == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Setting block.Td regardless of error (known for example) prevents errors down the line
|
||||
// in the protocol handler
|
||||
block.Td = new(big.Int).Set(CalcTD(block, self.GetBlock(block.ParentHash())))
|
||||
|
|
@ -542,7 +562,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
block.Td = new(big.Int)
|
||||
// Do not penelise on future block. We'll need a block queue eventually that will queue
|
||||
// future block for future use
|
||||
if err == BlockFutureErr {
|
||||
|
|
@ -559,17 +578,11 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
h := block.Header()
|
||||
|
||||
glog.V(logger.Error).Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes())
|
||||
glog.V(logger.Error).Infoln(err)
|
||||
glog.V(logger.Debug).Infoln(block)
|
||||
blockErr(block, err)
|
||||
|
||||
return i, err
|
||||
}
|
||||
|
||||
self.mu.Lock()
|
||||
{
|
||||
cblock := self.currentBlock
|
||||
// Write block to database. Eventually we'll have to improve on this and throw away blocks that are
|
||||
// not in the canonical chain.
|
||||
|
|
@ -614,13 +627,18 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
|
|||
queueEvent.sideCount++
|
||||
}
|
||||
self.futureBlocks.Delete(block.Hash())
|
||||
}
|
||||
self.mu.Unlock()
|
||||
|
||||
stats.processed++
|
||||
|
||||
}
|
||||
|
||||
// check and wait for the nonce error channel and
|
||||
// make sure no nonce error was thrown in the process
|
||||
err := <-nonceErrCh
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
|
||||
tend := time.Since(tstart)
|
||||
start, end := chain[0], chain[len(chain)-1]
|
||||
|
|
@ -719,3 +737,63 @@ out:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func blockErr(block *types.Block, err error) {
|
||||
h := block.Header()
|
||||
glog.V(logger.Error).Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes())
|
||||
glog.V(logger.Error).Infoln(err)
|
||||
glog.V(logger.Debug).Infoln(block)
|
||||
}
|
||||
|
||||
// verifyNonces verifies nonces of the given blocks in parallel and returns
|
||||
// an error if one of the blocks nonce verifications failed.
|
||||
func verifyNonces(pow pow.PoW, blocks []*types.Block) error {
|
||||
// Spawn a few workers. They listen for blocks on the in channel
|
||||
// and send results on done. The workers will exit in the
|
||||
// background when in is closed.
|
||||
var (
|
||||
in = make(chan *types.Block)
|
||||
done = make(chan error, runtime.GOMAXPROCS(0))
|
||||
)
|
||||
defer close(in)
|
||||
for i := 0; i < cap(done); i++ {
|
||||
go verifyNonce(pow, in, done)
|
||||
}
|
||||
// Feed blocks to the workers, aborting at the first invalid nonce.
|
||||
var (
|
||||
running, i int
|
||||
block *types.Block
|
||||
sendin = in
|
||||
)
|
||||
for i < len(blocks) || running > 0 {
|
||||
if i == len(blocks) {
|
||||
// Disable sending to in.
|
||||
sendin = nil
|
||||
} else {
|
||||
block = blocks[i]
|
||||
i++
|
||||
}
|
||||
select {
|
||||
case sendin <- block:
|
||||
running++
|
||||
case err := <-done:
|
||||
running--
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyNonce is a worker for the verifyNonces method. It will run until
|
||||
// in is closed.
|
||||
func verifyNonce(pow pow.PoW, in <-chan *types.Block, done chan<- error) {
|
||||
for block := range in {
|
||||
if !pow.Verify(block) {
|
||||
done <- ValidationError("Block(#%v) nonce is invalid (= %x)", block.Number(), block.Nonce)
|
||||
} else {
|
||||
done <- nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ import (
|
|||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -21,6 +23,11 @@ func init() {
|
|||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
}
|
||||
|
||||
func thePow() pow.PoW {
|
||||
pow, _ := ethash.NewForTesting()
|
||||
return pow
|
||||
}
|
||||
|
||||
// Test fork of length N starting from block i
|
||||
func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
|
||||
// switch databases to process the new chain
|
||||
|
|
@ -259,7 +266,7 @@ func TestChainInsertions(t *testing.T) {
|
|||
}
|
||||
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, thePow(), &eventMux)
|
||||
txPool := NewTxPool(&eventMux, chainMan.State, func() *big.Int { return big.NewInt(100000000) })
|
||||
blockMan := NewBlockProcessor(db, db, nil, txPool, chainMan, &eventMux)
|
||||
chainMan.SetProcessor(blockMan)
|
||||
|
|
@ -305,7 +312,7 @@ func TestChainMultipleInsertions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, thePow(), &eventMux)
|
||||
txPool := NewTxPool(&eventMux, chainMan.State, func() *big.Int { return big.NewInt(100000000) })
|
||||
blockMan := NewBlockProcessor(db, db, nil, txPool, chainMan, &eventMux)
|
||||
chainMan.SetProcessor(blockMan)
|
||||
|
|
@ -334,7 +341,7 @@ func TestGetAncestors(t *testing.T) {
|
|||
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, thePow(), &eventMux)
|
||||
chain, err := loadChain("valid1", t)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
|
@ -372,7 +379,7 @@ func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block
|
|||
|
||||
func chm(genesis *types.Block, db common.Database) *ChainManager {
|
||||
var eventMux event.TypeMux
|
||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: &eventMux}
|
||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
|
||||
bc.cache = NewBlockCache(100)
|
||||
bc.futureBlocks = NewBlockCache(100)
|
||||
bc.processor = bproc{}
|
||||
|
|
@ -383,6 +390,7 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
|
|||
}
|
||||
|
||||
func TestReorgLongest(t *testing.T) {
|
||||
t.Skip("skipped while cache is removed")
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
genesis := GenesisBlock(db)
|
||||
bc := chm(genesis, db)
|
||||
|
|
@ -402,6 +410,7 @@ func TestReorgLongest(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReorgShortest(t *testing.T) {
|
||||
t.Skip("skipped while cache is removed")
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
genesis := GenesisBlock(db)
|
||||
bc := chm(genesis, db)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, acco
|
|||
code := self.input
|
||||
self.input = nil
|
||||
ret, err = self.exec(nil, code, caller)
|
||||
// Here we get an error if we run into maximum stack depth,
|
||||
// See: https://github.com/ethereum/yellowpaper/pull/131
|
||||
// and YP definitions for CREATE instruction
|
||||
if err != nil {
|
||||
return nil, err, nil
|
||||
}
|
||||
account = self.env.State().GetStateObject(*self.address)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
21
core/vm/disasm.go
Normal file
21
core/vm/disasm.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package vm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Disasm(code []byte) []string {
|
||||
var out []string
|
||||
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
||||
op := OpCode(code[pc])
|
||||
out = append(out, op.String())
|
||||
|
||||
switch op {
|
||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||
a := uint64(op) - uint64(PUSH1) + 1
|
||||
out = append(out, fmt.Sprintf("0x%x", code[pc+1:pc+1+a]))
|
||||
|
||||
pc += a
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
|
@ -49,6 +49,18 @@ func (self *Memory) Get(offset, size int64) (cpy []byte) {
|
|||
return
|
||||
}
|
||||
|
||||
func (self *Memory) GetPtr(offset, size int64) []byte {
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(self.store) > int(offset) {
|
||||
return self.store[offset : offset+size]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Memory) Len() int {
|
||||
return len(m.store)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -695,7 +695,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
|||
self.Printf("resume %x (%v)", context.Address(), context.Gas)
|
||||
case RETURN:
|
||||
offset, size := stack.pop(), stack.pop()
|
||||
ret := mem.Get(offset.Int64(), size.Int64())
|
||||
ret := mem.GetPtr(offset.Int64(), size.Int64())
|
||||
|
||||
self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
|
||||
|
||||
|
|
|
|||
114
eth/backend.go
114
eth/backend.go
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/bzz"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/compiler"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -31,6 +32,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/whisper"
|
||||
)
|
||||
|
||||
const (
|
||||
epochLength = 30000
|
||||
ethashRevision = 23
|
||||
|
||||
autoDAGcheckInterval = 10 * time.Hour
|
||||
autoDAGepochHeight = epochLength / 2
|
||||
)
|
||||
|
||||
var (
|
||||
jsonlogger = logger.NewJsonLogger()
|
||||
|
||||
|
|
@ -60,6 +69,7 @@ type Config struct {
|
|||
LogJSON string
|
||||
VmDebug bool
|
||||
NatSpec bool
|
||||
AutoDAG bool
|
||||
|
||||
MaxPeers int
|
||||
MaxPendingPeers int
|
||||
|
|
@ -81,6 +91,7 @@ type Config struct {
|
|||
GasPrice *big.Int
|
||||
MinerThreads int
|
||||
AccountManager *accounts.Manager
|
||||
SolcPath string
|
||||
|
||||
// NewDB is used to create databases.
|
||||
// If nil, the default is to create leveldb databases on disk.
|
||||
|
|
@ -185,6 +196,8 @@ type Ethereum struct {
|
|||
downloader *downloader.Downloader
|
||||
DPA *bzz.DPA
|
||||
netStore *bzz.NetStore
|
||||
SolcPath string
|
||||
solc *compiler.Solidity
|
||||
|
||||
net *p2p.Server
|
||||
eventMux *event.TypeMux
|
||||
|
|
@ -197,6 +210,8 @@ type Ethereum struct {
|
|||
MinerThreads int
|
||||
NatSpec bool
|
||||
DataDir string
|
||||
AutoDAG bool
|
||||
autodagquit chan bool
|
||||
etherbase common.Address
|
||||
clientVersion string
|
||||
ethVersionId int
|
||||
|
|
@ -213,7 +228,7 @@ func New(config *Config) (*Ethereum, error) {
|
|||
|
||||
// Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files)
|
||||
const dbCount = 3
|
||||
ethdb.OpenFileLimit = 256 / (dbCount + 1)
|
||||
ethdb.OpenFileLimit = 128 / (dbCount + 1)
|
||||
|
||||
newdb := config.NewDB
|
||||
if newdb == nil {
|
||||
|
|
@ -268,11 +283,13 @@ func New(config *Config) (*Ethereum, error) {
|
|||
netVersionId: config.NetworkId,
|
||||
NatSpec: config.NatSpec,
|
||||
MinerThreads: config.MinerThreads,
|
||||
SolcPath: config.SolcPath,
|
||||
AutoDAG: config.AutoDAG,
|
||||
}
|
||||
|
||||
eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux())
|
||||
eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock)
|
||||
eth.pow = ethash.New()
|
||||
eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.pow, eth.EventMux())
|
||||
eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock)
|
||||
eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
|
||||
eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.txPool, eth.chainManager, eth.EventMux())
|
||||
eth.chainManager.SetProcessor(eth.blockProcessor)
|
||||
|
|
@ -469,6 +486,10 @@ func (s *Ethereum) Start() error {
|
|||
// periodically flush databases
|
||||
go s.syncDatabases()
|
||||
|
||||
if s.AutoDAG {
|
||||
s.StartAutoDAG()
|
||||
}
|
||||
|
||||
// Start services
|
||||
go s.txPool.Start()
|
||||
s.protocolManager.Start()
|
||||
|
|
@ -553,6 +574,7 @@ func (s *Ethereum) Stop() {
|
|||
if s.whisper != nil {
|
||||
s.whisper.Stop()
|
||||
}
|
||||
s.StopAutoDAG()
|
||||
|
||||
if s.DPA != nil {
|
||||
s.DPA.Stop()
|
||||
|
|
@ -593,6 +615,77 @@ func (self *Ethereum) syncAccounts(tx *types.Transaction) {
|
|||
}
|
||||
}
|
||||
|
||||
// StartAutoDAG() spawns a go routine that checks the DAG every autoDAGcheckInterval
|
||||
// by default that is 10 times per epoch
|
||||
// in epoch n, if we past autoDAGepochHeight within-epoch blocks,
|
||||
// it calls ethash.MakeDAG to pregenerate the DAG for the next epoch n+1
|
||||
// if it does not exist yet as well as remove the DAG for epoch n-1
|
||||
// the loop quits if autodagquit channel is closed, it can safely restart and
|
||||
// stop any number of times.
|
||||
// For any more sophisticated pattern of DAG generation, use CLI subcommand
|
||||
// makedag
|
||||
func (self *Ethereum) StartAutoDAG() {
|
||||
if self.autodagquit != nil {
|
||||
return // already started
|
||||
}
|
||||
go func() {
|
||||
glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG ON (ethash dir: %s)", ethash.DefaultDir)
|
||||
var nextEpoch uint64
|
||||
timer := time.After(0)
|
||||
self.autodagquit = make(chan bool)
|
||||
for {
|
||||
select {
|
||||
case <-timer:
|
||||
glog.V(logger.Info).Infof("checking DAG (ethash dir: %s)", ethash.DefaultDir)
|
||||
currentBlock := self.ChainManager().CurrentBlock().NumberU64()
|
||||
thisEpoch := currentBlock / epochLength
|
||||
if nextEpoch <= thisEpoch {
|
||||
if currentBlock%epochLength > autoDAGepochHeight {
|
||||
if thisEpoch > 0 {
|
||||
previousDag, previousDagFull := dagFiles(thisEpoch - 1)
|
||||
os.Remove(filepath.Join(ethash.DefaultDir, previousDag))
|
||||
os.Remove(filepath.Join(ethash.DefaultDir, previousDagFull))
|
||||
glog.V(logger.Info).Infof("removed DAG for epoch %d (%s)", thisEpoch-1, previousDag)
|
||||
}
|
||||
nextEpoch = thisEpoch + 1
|
||||
dag, _ := dagFiles(nextEpoch)
|
||||
if _, err := os.Stat(dag); os.IsNotExist(err) {
|
||||
glog.V(logger.Info).Infof("Pregenerating DAG for epoch %d (%s)", nextEpoch, dag)
|
||||
err := ethash.MakeDAG(nextEpoch*epochLength, "") // "" -> ethash.DefaultDir
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Error generating DAG for epoch %d (%s)", nextEpoch, dag)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
glog.V(logger.Error).Infof("DAG for epoch %d (%s)", nextEpoch, dag)
|
||||
}
|
||||
}
|
||||
}
|
||||
timer = time.After(autoDAGcheckInterval)
|
||||
case <-self.autodagquit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
|
||||
// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
|
||||
func dagFiles(epoch uint64) (string, string) {
|
||||
seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
|
||||
dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
|
||||
return dag, "full-R" + dag
|
||||
}
|
||||
|
||||
// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
|
||||
func (self *Ethereum) StopAutoDAG() {
|
||||
if self.autodagquit != nil {
|
||||
close(self.autodagquit)
|
||||
self.autodagquit = nil
|
||||
}
|
||||
glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
|
||||
}
|
||||
|
||||
func saveProtocolVersion(db common.Database, protov int) {
|
||||
d, _ := db.Get([]byte("ProtocolVersion"))
|
||||
protocolVersion := common.NewValue(d).Uint()
|
||||
|
|
@ -610,3 +703,18 @@ func saveBlockchainVersion(db common.Database, bcVersion int) {
|
|||
db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Ethereum) Solc() (*compiler.Solidity, error) {
|
||||
var err error
|
||||
if self.solc == nil {
|
||||
self.solc, err = compiler.New(self.SolcPath)
|
||||
}
|
||||
return self.solc, err
|
||||
}
|
||||
|
||||
// set in js console via admin interface or wrapper from cli flags
|
||||
func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
|
||||
self.SolcPath = solcPath
|
||||
self.solc = nil
|
||||
return self.Solc()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
maxHashFetch = 512 // Amount of hashes to be fetched per chunk
|
||||
maxBlockFetch = 128 // Amount of blocks to be fetched per chunk
|
||||
MinHashFetch = 512 // Minimum amount of hashes to not consider a peer stalling
|
||||
MaxHashFetch = 2048 // Amount of hashes to be fetched per retrieval request
|
||||
MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request
|
||||
|
||||
peerCountTimeout = 12 * time.Second // Amount of time it takes for the peer handler to ignore minDesiredPeerCount
|
||||
hashTTL = 5 * time.Second // Time it takes for a hash request to time out
|
||||
)
|
||||
|
|
@ -28,10 +30,11 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
errLowTd = errors.New("peer's TD is too low")
|
||||
errLowTd = errors.New("peers TD is too low")
|
||||
ErrBusy = errors.New("busy")
|
||||
errUnknownPeer = errors.New("peer's unknown or unhealthy")
|
||||
errUnknownPeer = errors.New("peer is unknown or unhealthy")
|
||||
ErrBadPeer = errors.New("action from bad peer ignored")
|
||||
ErrStallingPeer = errors.New("peer is stalling")
|
||||
errNoPeers = errors.New("no peers to keep download active")
|
||||
ErrPendingQueue = errors.New("pending items in queue")
|
||||
ErrTimeout = errors.New("timeout")
|
||||
|
|
@ -60,13 +63,18 @@ type hashPack struct {
|
|||
hashes []common.Hash
|
||||
}
|
||||
|
||||
type crossCheck struct {
|
||||
expire time.Time
|
||||
parent common.Hash
|
||||
}
|
||||
|
||||
type Downloader struct {
|
||||
mux *event.TypeMux
|
||||
|
||||
mu sync.RWMutex
|
||||
queue *queue // Scheduler for selecting the hashes to download
|
||||
peers *peerSet // Set of active peers from which download can proceed
|
||||
checks map[common.Hash]time.Time // Pending cross checks to verify a hash chain
|
||||
checks map[common.Hash]*crossCheck // Pending cross checks to verify a hash chain
|
||||
|
||||
// Callbacks
|
||||
hasBlock hashCheckFn
|
||||
|
|
@ -157,7 +165,7 @@ func (d *Downloader) Synchronise(id string, hash common.Hash) error {
|
|||
// Reset the queue and peer set to clean any internal leftover state
|
||||
d.queue.Reset()
|
||||
d.peers.Reset()
|
||||
d.checks = make(map[common.Hash]time.Time)
|
||||
d.checks = make(map[common.Hash]*crossCheck)
|
||||
|
||||
// Retrieve the origin peer and initiate the downloading process
|
||||
p := d.peers.Peer(id)
|
||||
|
|
@ -283,15 +291,22 @@ func (d *Downloader) fetchHashes(p *peer, h common.Hash) error {
|
|||
return ErrBadPeer
|
||||
}
|
||||
if !done {
|
||||
// Check that the peer is not stalling the sync
|
||||
if len(inserts) < MinHashFetch {
|
||||
return ErrStallingPeer
|
||||
}
|
||||
// Try and fetch a random block to verify the hash batch
|
||||
// Skip the last hash as the cross check races with the next hash fetch
|
||||
if len(inserts) > 1 {
|
||||
cross := inserts[rand.Intn(len(inserts)-1)]
|
||||
glog.V(logger.Detail).Infof("Cross checking (%s) with %x", active.id, cross)
|
||||
cross := rand.Intn(len(inserts) - 1)
|
||||
origin, parent := inserts[cross], inserts[cross+1]
|
||||
glog.V(logger.Detail).Infof("Cross checking (%s) with %x/%x", active.id, origin, parent)
|
||||
|
||||
d.checks[cross] = time.Now().Add(blockTTL)
|
||||
active.getBlocks([]common.Hash{cross})
|
||||
d.checks[origin] = &crossCheck{
|
||||
expire: time.Now().Add(blockTTL),
|
||||
parent: parent,
|
||||
}
|
||||
active.getBlocks([]common.Hash{origin})
|
||||
|
||||
// Also fetch a fresh
|
||||
active.getHashes(head)
|
||||
continue
|
||||
|
|
@ -310,8 +325,8 @@ func (d *Downloader) fetchHashes(p *peer, h common.Hash) error {
|
|||
continue
|
||||
}
|
||||
block := blockPack.blocks[0]
|
||||
if _, ok := d.checks[block.Hash()]; ok {
|
||||
if !d.queue.Has(block.ParentHash()) {
|
||||
if check, ok := d.checks[block.Hash()]; ok {
|
||||
if block.ParentHash() != check.parent {
|
||||
return ErrCrossCheckFailed
|
||||
}
|
||||
delete(d.checks, block.Hash())
|
||||
|
|
@ -319,8 +334,8 @@ func (d *Downloader) fetchHashes(p *peer, h common.Hash) error {
|
|||
|
||||
case <-crossTicker.C:
|
||||
// Iterate over all the cross checks and fail the hash chain if they're not verified
|
||||
for hash, deadline := range d.checks {
|
||||
if time.Now().After(deadline) {
|
||||
for hash, check := range d.checks {
|
||||
if time.Now().After(check.expire) {
|
||||
glog.V(logger.Debug).Infof("Cross check timeout for %x", hash)
|
||||
return ErrCrossCheckFailed
|
||||
}
|
||||
|
|
@ -438,7 +453,7 @@ out:
|
|||
}
|
||||
// Get a possible chunk. If nil is returned no chunk
|
||||
// could be returned due to no hashes available.
|
||||
request := d.queue.Reserve(peer, maxBlockFetch)
|
||||
request := d.queue.Reserve(peer, MaxBlockFetch)
|
||||
if request == nil {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ type downloadTester struct {
|
|||
blocks map[common.Hash]*types.Block // Blocks associated with the hashes
|
||||
chain []common.Hash // Block-chain being constructed
|
||||
|
||||
maxHashFetch int // Overrides the maximum number of retrieved hashes
|
||||
|
||||
t *testing.T
|
||||
pcount int
|
||||
done chan bool
|
||||
|
|
@ -133,8 +135,12 @@ func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
|
|||
|
||||
// getHashes retrieves a batch of hashes for reconstructing the chain.
|
||||
func (dl *downloadTester) getHashes(head common.Hash) error {
|
||||
limit := MaxHashFetch
|
||||
if dl.maxHashFetch > 0 {
|
||||
limit = dl.maxHashFetch
|
||||
}
|
||||
// Gather the next batch of hashes
|
||||
hashes := make([]common.Hash, 0, maxHashFetch)
|
||||
hashes := make([]common.Hash, 0, limit)
|
||||
for i, hash := range dl.hashes {
|
||||
if hash == head {
|
||||
i++
|
||||
|
|
@ -382,7 +388,7 @@ func TestRepeatingHashAttack(t *testing.T) {
|
|||
|
||||
// Make sure that syncing returns and does so with a failure
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("synchronisation blocked")
|
||||
case err := <-errc:
|
||||
if err == nil {
|
||||
|
|
@ -469,6 +475,23 @@ func TestMadeupHashChainAttack(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Tests that if a malicious peer makes up a random hash chain, and tries to push
|
||||
// indefinitely, one hash at a time, it actually gets caught with it. The reason
|
||||
// this is separate from the classical made up chain attack is that sending hashes
|
||||
// one by one prevents reliable block/parent verification.
|
||||
func TestMadeupHashChainDrippingAttack(t *testing.T) {
|
||||
// Create a random chain of hashes to drip
|
||||
hashes := createHashes(0, 16*blockCacheLimit)
|
||||
tester := newTester(t, hashes, nil)
|
||||
|
||||
// Try and sync with the attacker, one hash at a time
|
||||
tester.maxHashFetch = 1
|
||||
tester.newPeer("attack", big.NewInt(10000), hashes[0])
|
||||
if _, err := tester.syncTake("attack", hashes[0]); err != ErrStallingPeer {
|
||||
t.Fatalf("synchronisation error mismatch: have %v, want %v", err, ErrStallingPeer)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if a malicious peer makes up a random block chain, and tried to
|
||||
// push indefinitely, it actually gets caught with it.
|
||||
func TestMadeupBlockChainAttack(t *testing.T) {
|
||||
|
|
@ -479,7 +502,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
|
|||
crossCheckCycle = 25 * time.Millisecond
|
||||
|
||||
// Create a long chain of blocks and simulate an invalid chain by dropping every second
|
||||
hashes := createHashes(0, 32*blockCacheLimit)
|
||||
hashes := createHashes(0, 16*blockCacheLimit)
|
||||
blocks := createBlocksFromHashes(hashes)
|
||||
|
||||
gapped := make([]common.Hash, len(hashes)/2)
|
||||
|
|
@ -502,3 +525,37 @@ func TestMadeupBlockChainAttack(t *testing.T) {
|
|||
t.Fatalf("failed to synchronise blocks: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Advanced form of the above forged blockchain attack, where not only does the
|
||||
// attacker make up a valid hashes for random blocks, but also forges the block
|
||||
// parents to point to existing hashes.
|
||||
func TestMadeupParentBlockChainAttack(t *testing.T) {
|
||||
defaultBlockTTL := blockTTL
|
||||
defaultCrossCheckCycle := crossCheckCycle
|
||||
|
||||
blockTTL = 100 * time.Millisecond
|
||||
crossCheckCycle = 25 * time.Millisecond
|
||||
|
||||
// Create a long chain of blocks and simulate an invalid chain by dropping every second
|
||||
hashes := createHashes(0, 16*blockCacheLimit)
|
||||
blocks := createBlocksFromHashes(hashes)
|
||||
forges := createBlocksFromHashes(hashes)
|
||||
for hash, block := range forges {
|
||||
block.ParentHeaderHash = hash // Simulate pointing to already known hash
|
||||
}
|
||||
// Try and sync with the malicious node and check that it fails
|
||||
tester := newTester(t, hashes, forges)
|
||||
tester.newPeer("attack", big.NewInt(10000), hashes[0])
|
||||
if _, err := tester.syncTake("attack", hashes[0]); err != ErrCrossCheckFailed {
|
||||
t.Fatalf("synchronisation error mismatch: have %v, want %v", err, ErrCrossCheckFailed)
|
||||
}
|
||||
// Ensure that a valid chain can still pass sync
|
||||
blockTTL = defaultBlockTTL
|
||||
crossCheckCycle = defaultCrossCheckCycle
|
||||
|
||||
tester.blocks = blocks
|
||||
tester.newPeer("valid", big.NewInt(20000), hashes[0])
|
||||
if _, err := tester.syncTake("valid", hashes[0]); err != nil {
|
||||
t.Fatalf("failed to synchronise blocks: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
blockCacheLimit = 1024 // Maximum number of blocks to cache before throttling the download
|
||||
blockCacheLimit = 8 * MaxBlockFetch // Maximum number of blocks to cache before throttling the download
|
||||
)
|
||||
|
||||
// fetchRequest is a currently running block retrieval operation.
|
||||
|
|
|
|||
|
|
@ -47,9 +47,7 @@ type ProtocolManager struct {
|
|||
txpool txPool
|
||||
chainman *core.ChainManager
|
||||
downloader *downloader.Downloader
|
||||
|
||||
pmu sync.Mutex
|
||||
peers map[string]*peer
|
||||
peers *peerSet
|
||||
|
||||
SubProtocol p2p.Protocol
|
||||
|
||||
|
|
@ -73,7 +71,7 @@ func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpo
|
|||
txpool: txpool,
|
||||
chainman: chainman,
|
||||
downloader: downloader,
|
||||
peers: make(map[string]*peer),
|
||||
peers: newPeerSet(),
|
||||
newPeerCh: make(chan *peer, 1),
|
||||
quitSync: make(chan struct{}),
|
||||
}
|
||||
|
|
@ -95,10 +93,14 @@ func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpo
|
|||
}
|
||||
|
||||
func (pm *ProtocolManager) removePeer(peer *peer) {
|
||||
pm.pmu.Lock()
|
||||
defer pm.pmu.Unlock()
|
||||
// Unregister the peer from the downloader
|
||||
pm.downloader.UnregisterPeer(peer.id)
|
||||
delete(pm.peers, peer.id)
|
||||
|
||||
// Remove the peer from the Ethereum peer set too
|
||||
glog.V(logger.Detail).Infoln("Removing peer", peer.id)
|
||||
if err := pm.peers.Unregister(peer.id); err != nil {
|
||||
glog.V(logger.Error).Infoln("Removal failed:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *ProtocolManager) Start() {
|
||||
|
|
@ -136,31 +138,32 @@ func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter
|
|||
}
|
||||
|
||||
func (pm *ProtocolManager) handle(p *peer) error {
|
||||
// Execute the Ethereum handshake, short circuit if fails
|
||||
if err := p.handleStatus(); err != nil {
|
||||
return err
|
||||
}
|
||||
pm.pmu.Lock()
|
||||
pm.peers[p.id] = p
|
||||
pm.pmu.Unlock()
|
||||
|
||||
pm.downloader.RegisterPeer(p.id, p.recentHash, p.requestHashes, p.requestBlocks)
|
||||
defer func() {
|
||||
pm.removePeer(p)
|
||||
}()
|
||||
// Register the peer locally and in the downloader too
|
||||
glog.V(logger.Detail).Infoln("Adding peer", p.id)
|
||||
if err := pm.peers.Register(p); err != nil {
|
||||
glog.V(logger.Error).Infoln("Addition failed:", err)
|
||||
return err
|
||||
}
|
||||
defer pm.removePeer(p)
|
||||
|
||||
if err := pm.downloader.RegisterPeer(p.id, p.recentHash, p.requestHashes, p.requestBlocks); err != nil {
|
||||
return err
|
||||
}
|
||||
// propagate existing transactions. new transactions appearing
|
||||
// after this will be sent via broadcasts.
|
||||
if err := p.sendTransactions(pm.txpool.GetTransactions()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// main loop. handle incoming messages.
|
||||
for {
|
||||
if err := pm.handleMsg(p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -203,8 +206,8 @@ func (self *ProtocolManager) handleMsg(p *peer) error {
|
|||
return errResp(ErrDecode, "->msg %v: %v", msg, err)
|
||||
}
|
||||
|
||||
if request.Amount > maxHashes {
|
||||
request.Amount = maxHashes
|
||||
if request.Amount > downloader.MaxHashFetch {
|
||||
request.Amount = downloader.MaxHashFetch
|
||||
}
|
||||
|
||||
hashes := self.chainman.GetBlockHashesFromHash(request.Hash, request.Amount)
|
||||
|
|
@ -251,7 +254,7 @@ func (self *ProtocolManager) handleMsg(p *peer) error {
|
|||
if block != nil {
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
if i == maxBlocks {
|
||||
if i == downloader.MaxBlockFetch {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -346,18 +349,8 @@ func (pm *ProtocolManager) verifyTd(peer *peer, request newBlockMsgData) error {
|
|||
// out which peers do not contain the block in their block set and will do a
|
||||
// sqrt(peers) to determine the amount of peers we broadcast to.
|
||||
func (pm *ProtocolManager) BroadcastBlock(hash common.Hash, block *types.Block) {
|
||||
pm.pmu.Lock()
|
||||
defer pm.pmu.Unlock()
|
||||
|
||||
// Find peers who don't know anything about the given hash. Peers that
|
||||
// don't know about the hash will be a candidate for the broadcast loop
|
||||
var peers []*peer
|
||||
for _, peer := range pm.peers {
|
||||
if !peer.blockHashes.Has(hash) {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
// Broadcast block to peer set
|
||||
// Broadcast block to a batch of peers not knowing about it
|
||||
peers := pm.peers.PeersWithoutBlock(hash)
|
||||
peers = peers[:int(math.Sqrt(float64(len(peers))))]
|
||||
for _, peer := range peers {
|
||||
peer.sendNewBlock(block)
|
||||
|
|
@ -369,18 +362,8 @@ func (pm *ProtocolManager) BroadcastBlock(hash common.Hash, block *types.Block)
|
|||
// out which peers do not contain the block in their block set and will do a
|
||||
// sqrt(peers) to determine the amount of peers we broadcast to.
|
||||
func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction) {
|
||||
pm.pmu.Lock()
|
||||
defer pm.pmu.Unlock()
|
||||
|
||||
// Find peers who don't know anything about the given hash. Peers that
|
||||
// don't know about the hash will be a candidate for the broadcast loop
|
||||
var peers []*peer
|
||||
for _, peer := range pm.peers {
|
||||
if !peer.txHashes.Has(hash) {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
// Broadcast block to peer set
|
||||
// Broadcast transaction to a batch of peers not knowing about it
|
||||
peers := pm.peers.PeersWithoutTx(hash)
|
||||
//FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))]
|
||||
for _, peer := range peers {
|
||||
peer.sendTransaction(tx)
|
||||
|
|
|
|||
122
eth/peer.go
122
eth/peer.go
|
|
@ -1,17 +1,25 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"gopkg.in/fatih/set.v0"
|
||||
)
|
||||
|
||||
var (
|
||||
errAlreadyRegistered = errors.New("peer is already registered")
|
||||
errNotRegistered = errors.New("peer is not registered")
|
||||
)
|
||||
|
||||
type statusMsgData struct {
|
||||
ProtocolVersion uint32
|
||||
NetworkId uint32
|
||||
|
|
@ -25,16 +33,6 @@ type getBlockHashesMsgData struct {
|
|||
Amount uint64
|
||||
}
|
||||
|
||||
func getBestPeer(peers map[string]*peer) *peer {
|
||||
var peer *peer
|
||||
for _, cp := range peers {
|
||||
if peer == nil || cp.td.Cmp(peer.td) > 0 {
|
||||
peer = cp
|
||||
}
|
||||
}
|
||||
return peer
|
||||
}
|
||||
|
||||
type peer struct {
|
||||
*p2p.Peer
|
||||
|
||||
|
|
@ -103,8 +101,8 @@ func (p *peer) sendTransaction(tx *types.Transaction) error {
|
|||
}
|
||||
|
||||
func (p *peer) requestHashes(from common.Hash) error {
|
||||
glog.V(logger.Debug).Infof("[%s] fetching hashes (%d) %x...\n", p.id, maxHashes, from[:4])
|
||||
return p2p.Send(p.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes})
|
||||
glog.V(logger.Debug).Infof("[%s] fetching hashes (%d) %x...\n", p.id, downloader.MaxHashFetch, from[:4])
|
||||
return p2p.Send(p.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, downloader.MaxHashFetch})
|
||||
}
|
||||
|
||||
func (p *peer) requestBlocks(hashes []common.Hash) error {
|
||||
|
|
@ -159,3 +157,103 @@ func (p *peer) handleStatus() error {
|
|||
|
||||
return <-errc
|
||||
}
|
||||
|
||||
// peerSet represents the collection of active peers currently participating in
|
||||
// the Ethereum sub-protocol.
|
||||
type peerSet struct {
|
||||
peers map[string]*peer
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// newPeerSet creates a new peer set to track the active participants.
|
||||
func newPeerSet() *peerSet {
|
||||
return &peerSet{
|
||||
peers: make(map[string]*peer),
|
||||
}
|
||||
}
|
||||
|
||||
// Register injects a new peer into the working set, or returns an error if the
|
||||
// peer is already known.
|
||||
func (ps *peerSet) Register(p *peer) error {
|
||||
ps.lock.Lock()
|
||||
defer ps.lock.Unlock()
|
||||
|
||||
if _, ok := ps.peers[p.id]; ok {
|
||||
return errAlreadyRegistered
|
||||
}
|
||||
ps.peers[p.id] = p
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unregister removes a remote peer from the active set, disabling any further
|
||||
// actions to/from that particular entity.
|
||||
func (ps *peerSet) Unregister(id string) error {
|
||||
ps.lock.Lock()
|
||||
defer ps.lock.Unlock()
|
||||
|
||||
if _, ok := ps.peers[id]; !ok {
|
||||
return errNotRegistered
|
||||
}
|
||||
delete(ps.peers, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Peer retrieves the registered peer with the given id.
|
||||
func (ps *peerSet) Peer(id string) *peer {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
|
||||
return ps.peers[id]
|
||||
}
|
||||
|
||||
// Len returns if the current number of peers in the set.
|
||||
func (ps *peerSet) Len() int {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
|
||||
return len(ps.peers)
|
||||
}
|
||||
|
||||
// PeersWithoutBlock retrieves a list of peers that do not have a given block in
|
||||
// their set of known hashes.
|
||||
func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
|
||||
list := make([]*peer, 0, len(ps.peers))
|
||||
for _, p := range ps.peers {
|
||||
if !p.blockHashes.Has(hash) {
|
||||
list = append(list, p)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// PeersWithoutTx retrieves a list of peers that do not have a given transaction
|
||||
// in their set of known hashes.
|
||||
func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
|
||||
list := make([]*peer, 0, len(ps.peers))
|
||||
for _, p := range ps.peers {
|
||||
if !p.txHashes.Has(hash) {
|
||||
list = append(list, p)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// BestPeer retrieves the known peer with the currently highest total difficulty.
|
||||
func (ps *peerSet) BestPeer() *peer {
|
||||
ps.lock.RLock()
|
||||
defer ps.lock.RUnlock()
|
||||
|
||||
var best *peer
|
||||
for _, p := range ps.peers {
|
||||
if best == nil || p.td.Cmp(best.td) > 0 {
|
||||
best = p
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ const (
|
|||
NetworkId = 100
|
||||
ProtocolLength = uint64(8)
|
||||
ProtocolMaxMsgSize = 10 * 1024 * 1024
|
||||
maxHashes = 512
|
||||
maxBlocks = 128
|
||||
)
|
||||
|
||||
// eth protocol message codes
|
||||
|
|
|
|||
36
eth/sync.go
36
eth/sync.go
|
|
@ -10,8 +10,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
)
|
||||
|
||||
// Sync contains all synchronisation code for the eth protocol
|
||||
|
||||
// update periodically tries to synchronise with the network, both downloading
|
||||
// hashes and blocks as well as retrieving cached ones.
|
||||
func (pm *ProtocolManager) update() {
|
||||
forceSync := time.Tick(forceSyncCycle)
|
||||
blockProc := time.Tick(blockProcCycle)
|
||||
|
|
@ -20,22 +20,16 @@ func (pm *ProtocolManager) update() {
|
|||
for {
|
||||
select {
|
||||
case <-pm.newPeerCh:
|
||||
// Meet the `minDesiredPeerCount` before we select our best peer
|
||||
if len(pm.peers) < minDesiredPeerCount {
|
||||
// Make sure we have peers to select from, then sync
|
||||
if pm.peers.Len() < minDesiredPeerCount {
|
||||
break
|
||||
}
|
||||
// Find the best peer and synchronise with it
|
||||
peer := getBestPeer(pm.peers)
|
||||
if peer == nil {
|
||||
glog.V(logger.Debug).Infoln("Sync attempt canceled. No peers available")
|
||||
}
|
||||
go pm.synchronise(peer)
|
||||
go pm.synchronise(pm.peers.BestPeer())
|
||||
|
||||
case <-forceSync:
|
||||
// Force a sync even if not enough peers are present
|
||||
if peer := getBestPeer(pm.peers); peer != nil {
|
||||
go pm.synchronise(peer)
|
||||
}
|
||||
go pm.synchronise(pm.peers.BestPeer())
|
||||
|
||||
case <-blockProc:
|
||||
// Try to pull some blocks from the downloaded
|
||||
if atomic.CompareAndSwapInt32(&blockProcPend, 0, 1) {
|
||||
|
|
@ -51,10 +45,9 @@ func (pm *ProtocolManager) update() {
|
|||
}
|
||||
}
|
||||
|
||||
// processBlocks will attempt to reconstruct a chain by checking the first item and check if it's
|
||||
// a known parent. The first block in the chain may be unknown during downloading. When the
|
||||
// downloader isn't downloading blocks will be dropped with an unknown parent until either it
|
||||
// has depleted the list or found a known parent.
|
||||
// processBlocks retrieves downloaded blocks from the download cache and tries
|
||||
// to construct the local block chain with it. Note, since the block retrieval
|
||||
// order matters, access to this function *must* be synchronized/serialized.
|
||||
func (pm *ProtocolManager) processBlocks() error {
|
||||
pm.wg.Add(1)
|
||||
defer pm.wg.Done()
|
||||
|
|
@ -79,15 +72,24 @@ func (pm *ProtocolManager) processBlocks() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// synchronise tries to sync up our local block chain with a remote peer, both
|
||||
// adding various sanity checks as well as wrapping it with various log entries.
|
||||
func (pm *ProtocolManager) synchronise(peer *peer) {
|
||||
// Short circuit if no peers are available
|
||||
if peer == nil {
|
||||
glog.V(logger.Debug).Infoln("Synchronisation canceled: no peers available")
|
||||
return
|
||||
}
|
||||
// Make sure the peer's TD is higher than our own. If not drop.
|
||||
if peer.td.Cmp(pm.chainman.Td()) <= 0 {
|
||||
glog.V(logger.Debug).Infoln("Synchronisation canceled: peer TD too small")
|
||||
return
|
||||
}
|
||||
// FIXME if we have the hash in our chain and the TD of the peer is
|
||||
// much higher than ours, something is wrong with us or the peer.
|
||||
// Check if the hash is on our own chain
|
||||
if pm.chainman.HasBlock(peer.recentHash) {
|
||||
glog.V(logger.Debug).Infoln("Synchronisation canceled: head already known")
|
||||
return
|
||||
}
|
||||
// Get the hashes from the peer (synchronously)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||
)
|
||||
|
|
@ -24,9 +25,17 @@ type LDBDatabase struct {
|
|||
quit chan struct{}
|
||||
}
|
||||
|
||||
// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
|
||||
// it self but requires a background poller which syncs every X. `Flush` should be called
|
||||
// when data needs to be stored and written to disk.
|
||||
func NewLDBDatabase(file string) (*LDBDatabase, error) {
|
||||
// Open the db
|
||||
db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
|
||||
// check for curruption and attempt to recover
|
||||
if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted {
|
||||
db, err = leveldb.RecoverFile(file, nil)
|
||||
}
|
||||
// (re) check for errors and abort if opening of the db failed
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -44,21 +53,15 @@ func (self *LDBDatabase) makeQueue() {
|
|||
self.queue = make(map[string][]byte)
|
||||
}
|
||||
|
||||
// Put puts the given key / value to the queue
|
||||
func (self *LDBDatabase) Put(key []byte, value []byte) {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
|
||||
self.queue[string(key)] = value
|
||||
/*
|
||||
value = rle.Compress(value)
|
||||
|
||||
err := self.db.Put(key, value, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error put", err)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Get returns the given key if it's present.
|
||||
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
|
|
@ -76,6 +79,7 @@ func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
|
|||
return rle.Decompress(dat)
|
||||
}
|
||||
|
||||
// Delete deletes the key from the queue and database
|
||||
func (self *LDBDatabase) Delete(key []byte) error {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
|
|
@ -100,6 +104,7 @@ func (self *LDBDatabase) NewIterator() iterator.Iterator {
|
|||
return self.db.NewIterator(nil, nil)
|
||||
}
|
||||
|
||||
// Flush flushes out the queue to leveldb
|
||||
func (self *LDBDatabase) Flush() error {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
|
|
|
|||
2402
jsre/ethereum_js.go
2402
jsre/ethereum_js.go
File diff suppressed because it is too large
Load diff
|
|
@ -40,7 +40,6 @@ func (self *CpuAgent) Stop() {
|
|||
defer self.mu.Unlock()
|
||||
|
||||
close(self.quit)
|
||||
close(self.quitCurrentOp)
|
||||
}
|
||||
|
||||
func (self *CpuAgent) Start() {
|
||||
|
|
@ -50,7 +49,6 @@ func (self *CpuAgent) Start() {
|
|||
self.quit = make(chan struct{})
|
||||
// creating current op ch makes sure we're not closing a nil ch
|
||||
// later on
|
||||
self.quitCurrentOp = make(chan struct{})
|
||||
self.workCh = make(chan *types.Block, 1)
|
||||
|
||||
go self.update()
|
||||
|
|
@ -62,11 +60,19 @@ out:
|
|||
select {
|
||||
case block := <-self.workCh:
|
||||
self.mu.Lock()
|
||||
if self.quitCurrentOp != nil {
|
||||
close(self.quitCurrentOp)
|
||||
}
|
||||
self.quitCurrentOp = make(chan struct{})
|
||||
go self.mine(block, self.quitCurrentOp)
|
||||
self.mu.Unlock()
|
||||
|
||||
go self.mine(block)
|
||||
case <-self.quit:
|
||||
self.mu.Lock()
|
||||
if self.quitCurrentOp != nil {
|
||||
close(self.quitCurrentOp)
|
||||
self.quitCurrentOp = nil
|
||||
}
|
||||
self.mu.Unlock()
|
||||
break out
|
||||
}
|
||||
}
|
||||
|
|
@ -84,16 +90,11 @@ done:
|
|||
}
|
||||
}
|
||||
|
||||
func (self *CpuAgent) mine(block *types.Block) {
|
||||
func (self *CpuAgent) mine(block *types.Block, stop <- chan struct{}) {
|
||||
glog.V(logger.Debug).Infof("(re)started agent[%d]. mining...\n", self.index)
|
||||
|
||||
// Reset the channel
|
||||
self.mu.Lock()
|
||||
self.quitCurrentOp = make(chan struct{})
|
||||
self.mu.Unlock()
|
||||
|
||||
// Mine
|
||||
nonce, mixDigest := self.pow.Search(block, self.quitCurrentOp)
|
||||
nonce, mixDigest := self.pow.Search(block, stop)
|
||||
if nonce != 0 {
|
||||
block.SetNonce(nonce)
|
||||
block.Header().MixDigest = common.BytesToHash(mixDigest)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,13 @@ func New(eth core.Backend, mux *event.TypeMux, pow pow.PoW) *Miner {
|
|||
return miner
|
||||
}
|
||||
|
||||
// update keeps track of the downloader events. Please be aware that this is a one shot type of update loop.
|
||||
// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and
|
||||
// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks
|
||||
// and halt your mining operation for as long as the DOS continues.
|
||||
func (self *Miner) update() {
|
||||
events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
||||
out:
|
||||
for ev := range events.Chan() {
|
||||
switch ev.(type) {
|
||||
case downloader.StartEvent:
|
||||
|
|
@ -58,6 +63,10 @@ func (self *Miner) update() {
|
|||
if shouldStart {
|
||||
self.Start(self.coinbase, self.threads)
|
||||
}
|
||||
// unsubscribe. we're only interested in this event once
|
||||
events.Unsubscribe()
|
||||
// stop immediately and ignore all further pending events
|
||||
break out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,13 @@ func (self *worker) wait() {
|
|||
}
|
||||
self.mux.Post(core.NewMinedBlockEvent{block})
|
||||
|
||||
glog.V(logger.Info).Infof("🔨 Mined block #%v", block.Number())
|
||||
var stale string
|
||||
canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
|
||||
if canonBlock != nil && canonBlock.Hash() != block.Hash() {
|
||||
stale = "stale-"
|
||||
}
|
||||
|
||||
glog.V(logger.Info).Infof("🔨 Mined %sblock #%v (%x)", stale, block.Number(), block.Hash().Bytes()[:4])
|
||||
|
||||
jsonlogger.LogJson(&logger.EthMinerNewBlock{
|
||||
BlockHash: block.Hash().Hex(),
|
||||
|
|
@ -264,6 +270,7 @@ func (self *worker) makeCurrent() {
|
|||
}
|
||||
block.Header().Extra = self.extra
|
||||
|
||||
// when 08 is processed ancestors contain 07 (quick block)
|
||||
current := env(block, self.eth)
|
||||
for _, ancestor := range self.chain.GetAncestors(block, 7) {
|
||||
for _, uncle := range ancestor.Uncles() {
|
||||
|
|
|
|||
32
rpc/api.go
32
rpc/api.go
|
|
@ -1,11 +1,12 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
// "sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
|
|
@ -230,7 +231,14 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
|
||||
block := api.xeth().EthBlockByNumber(args.BlockNumber)
|
||||
br := NewBlockRes(block, args.IncludeTxs)
|
||||
|
||||
// If request was for "pending", nil nonsensical fields
|
||||
if args.BlockNumber == -2 {
|
||||
br.BlockHash = nil
|
||||
br.BlockNumber = nil
|
||||
br.Miner = nil
|
||||
br.Nonce = nil
|
||||
br.LogsBloom = nil
|
||||
}
|
||||
*reply = br
|
||||
case "eth_getTransactionByHash":
|
||||
args := new(HashArgs)
|
||||
|
|
@ -240,9 +248,12 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash)
|
||||
if tx != nil {
|
||||
v := NewTransactionRes(tx)
|
||||
// if the blockhash is 0, assume this is a pending transaction
|
||||
if bytes.Compare(bhash.Bytes(), bytes.Repeat([]byte{0}, 32)) != 0 {
|
||||
v.BlockHash = newHexData(bhash)
|
||||
v.BlockNumber = newHexNum(bnum)
|
||||
v.TxIndex = newHexNum(txi)
|
||||
}
|
||||
*reply = v
|
||||
}
|
||||
case "eth_getTransactionByBlockHashAndIndex":
|
||||
|
|
@ -334,10 +345,9 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
return NewNotImplementedError(req.Method)
|
||||
|
||||
case "eth_compileSolidity":
|
||||
|
||||
solc, _ := api.xeth().Solc()
|
||||
if solc == nil {
|
||||
return NewNotImplementedError(req.Method)
|
||||
return NewNotAvailableError(req.Method, "solc (solidity compiler) not found")
|
||||
}
|
||||
|
||||
args := new(SourceArgs)
|
||||
|
|
@ -345,12 +355,11 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
return err
|
||||
}
|
||||
|
||||
contract, err := solc.Compile(args.Source)
|
||||
contracts, err := solc.Compile(args.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contract.Code = newHexData(contract.Code).String()
|
||||
*reply = contract
|
||||
*reply = contracts
|
||||
|
||||
case "eth_newFilter":
|
||||
args := new(BlockFilterArgs)
|
||||
|
|
@ -553,6 +562,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
|
||||
case "eth_hashrate":
|
||||
*reply = newHexNum(api.xeth().HashRate())
|
||||
case "ext_disasm":
|
||||
args := new(SourceArgs)
|
||||
if err := json.Unmarshal(req.Params, &args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*reply = vm.Disasm(common.FromHex(args.Source))
|
||||
|
||||
// case "eth_register":
|
||||
// // Placeholder for actual type
|
||||
|
|
@ -577,7 +593,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||
return NewNotImplementedError(req.Method)
|
||||
}
|
||||
|
||||
glog.V(logger.Detail).Infof("Reply: %T %s\n", reply, reply)
|
||||
// glog.V(logger.Detail).Infof("Reply: %v\n", reply)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,11 @@ package rpc
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
// "sync"
|
||||
"testing"
|
||||
// "time"
|
||||
// "fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/compiler"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
|
|
@ -30,12 +27,15 @@ func TestWeb3Sha3(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const solcVersion = "0.9.23"
|
||||
|
||||
func TestCompileSolidity(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
solc, err := compiler.New("")
|
||||
if solc == nil {
|
||||
t.Skip("no solidity compiler")
|
||||
t.Skip("no solc found: skip")
|
||||
} else if solc.Version() != solcVersion {
|
||||
t.Logf("WARNING: solc different version found (%v, test written for %v, may need to update)", solc.Version(), solcVersion)
|
||||
}
|
||||
source := `contract test {\n` +
|
||||
" /// @notice Will multiply `a` by 7." + `\n` +
|
||||
|
|
@ -46,16 +46,16 @@ func TestCompileSolidity(t *testing.T) {
|
|||
|
||||
jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}`
|
||||
|
||||
//expCode := "605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056"
|
||||
expCode := "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"
|
||||
expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]`
|
||||
expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}`
|
||||
expDeveloperDoc := `{"methods":{}}`
|
||||
expCompilerVersion := `0.9.13`
|
||||
expCompilerVersion := solc.Version()
|
||||
expLanguage := "Solidity"
|
||||
expLanguageVersion := "0"
|
||||
expSource := source
|
||||
|
||||
api := NewEthereumApi(&xeth.XEth{})
|
||||
api := NewEthereumApi(xeth.NewTest(ð.Ethereum{}, nil))
|
||||
|
||||
var req RpcRequest
|
||||
json.Unmarshal([]byte(jsonstr), &req)
|
||||
|
|
@ -70,26 +70,34 @@ func TestCompileSolidity(t *testing.T) {
|
|||
t.Errorf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
var contract = compiler.Contract{}
|
||||
err = json.Unmarshal(respjson, &contract)
|
||||
var contracts = make(map[string]*compiler.Contract)
|
||||
err = json.Unmarshal(respjson, &contracts)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
/*
|
||||
if contract.Code != expCode {
|
||||
t.Errorf("Expected %s got %s", expCode, contract.Code)
|
||||
if len(contracts) != 1 {
|
||||
t.Errorf("expected one contract, got %v", len(contracts))
|
||||
}
|
||||
*/
|
||||
|
||||
contract := contracts["test"]
|
||||
|
||||
if contract.Code != expCode {
|
||||
t.Errorf("Expected \n%s got \n%s", expCode, contract.Code)
|
||||
}
|
||||
|
||||
if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` {
|
||||
t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source))
|
||||
}
|
||||
|
||||
if contract.Info.Language != expLanguage {
|
||||
t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language)
|
||||
}
|
||||
|
||||
if contract.Info.LanguageVersion != expLanguageVersion {
|
||||
t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion)
|
||||
}
|
||||
|
||||
if contract.Info.CompilerVersion != expCompilerVersion {
|
||||
t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion)
|
||||
}
|
||||
|
|
@ -112,8 +120,6 @@ func TestCompileSolidity(t *testing.T) {
|
|||
if string(abidef) != expAbiDefinition {
|
||||
t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef))
|
||||
}
|
||||
ioutil.WriteFile("/tmp/abidef", []byte(string(abidef)), 0700)
|
||||
ioutil.WriteFile("/tmp/expabidef", []byte(expAbiDefinition), 0700)
|
||||
|
||||
if string(userdoc) != expUserDoc {
|
||||
t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc))
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
|
|
@ -39,7 +40,7 @@ func Start(pipe *xeth.XEth, config RpcConfig) error {
|
|||
if len(config.CorsDomain) > 0 {
|
||||
var opts cors.Options
|
||||
opts.AllowedMethods = []string{"POST"}
|
||||
opts.AllowedOrigins = []string{config.CorsDomain}
|
||||
opts.AllowedOrigins = strings.Split(config.CorsDomain, " ")
|
||||
|
||||
c := cors.New(opts)
|
||||
handler = newStoppableHandler(c.Handler(JSONRPC(pipe)), l.stop)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ func TestBcTotalDifficulty(t *testing.T) {
|
|||
runBlockTestsInFile("files/BlockTests/bcTotalDifficultyTest.json", []string{}, t)
|
||||
}
|
||||
|
||||
func TestBcWallet(t *testing.T) {
|
||||
runBlockTestsInFile("files/BlockTests/bcWalletTest.json", []string{}, t)
|
||||
}
|
||||
|
||||
func runBlockTestsInFile(filepath string, snafus []string, t *testing.T) {
|
||||
bt, err := LoadBlockTests(filepath)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -924,6 +924,440 @@
|
|||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createFailBalanceTooLow" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a7640017",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x715d",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7638e8c",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "5833e19631ddedaf4e3c9a766f696c2e59e7524e388eb871be19dc8e0ce37b6e",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x605a60005360016000670de0b6b3a7640018f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0xcf1d",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x17"
|
||||
}
|
||||
},
|
||||
"createInitFailBadJumpDestination" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a76586a0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x05f58340",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a16cf620",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "ccf7765eff3effe22a5f853099f7da88291b8346b689ffbf54b729ba04170e59",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6056600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0x05f5e100",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createInitFailStackSizeLargerThan1024" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a76586a0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x05f58340",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a16cf620",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "ccf7765eff3effe22a5f853099f7da88291b8346b689ffbf54b729ba04170e59",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x7f6103ff6000525b7f0102030405060708090a0102030405060708090a010203046000527f05060708090a0102600160005103600052600051600657000000000000000000602052604060006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0x05f5e100",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createInitFailStackUnderflow" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a76586a0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x05f58340",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a16cf620",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "ccf7765eff3effe22a5f853099f7da88291b8346b689ffbf54b729ba04170e59",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6001600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0x05f5e100",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createInitFailUndefinedInstruction" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a76586a0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x05f58340",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a16cf620",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "ccf7765eff3effe22a5f853099f7da88291b8346b689ffbf54b729ba04170e59",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60f4600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0x05f5e100",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createInitFail_OOGduringInit" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x0de0b6b3a76586a0",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x715d",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7620803",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "297303455494578a5176177ff1b9db0b0a516255a3d062fb960bbc99e60d8eb5",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x605a600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0xcf1d",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createInitOOGforCREATE" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x05f5e100",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x605a600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0xcf1c",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a76330e4",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "b61e4a95fae40806b0ddef0883479c3db70e79e019ab4260535560827525c00c",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x605a600053600160006001f0ff",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"transaction" : {
|
||||
"data" : "",
|
||||
"gasLimit" : "0xcf1c",
|
||||
"gasPrice" : "0x01",
|
||||
"nonce" : "0x00",
|
||||
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
|
||||
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
|
||||
"value" : "0x0186a0"
|
||||
}
|
||||
},
|
||||
"createJS_ExampleContract" : {
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
|
|
|
|||
|
|
@ -266,35 +266,35 @@
|
|||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x00",
|
||||
"out" : "#4294967295",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6401000000016000f3",
|
||||
"code" : "0x63ffffffff6000f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0x200018085211",
|
||||
"balance" : "0x20001800520e",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x1869ec3b06114f6f",
|
||||
"balance" : "0x1869ec3b06194f72",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "8745f6bdec4290420747b8c024382c6ed14e09f4a11718bdc1f0f99e4d04607b",
|
||||
"postStateRoot" : "1716bcf6c106040a46ab1d37c569b7e0841f921b4d252dc5202fb05388308a39",
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6401000000016000f3",
|
||||
"code" : "0x63ffffffff6000f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
|
|
@ -328,11 +328,11 @@
|
|||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"out" : "#4294967295",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000526401000000006000f3",
|
||||
"code" : "0x600160005263ffffffff6000f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
|
|
@ -352,11 +352,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "e6c6c5b997cf7ecbc653c920a5b42d1ddd9f9ca2df2c68fd47059df2a3309b14",
|
||||
"postStateRoot" : "b95676d3103fc4a6bdcfb1c201a6ed49e0fa7a239520a4b8ac034ce3b6c697eb",
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000526401000000006000f3",
|
||||
"code" : "0x600160005263ffffffff6000f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -268,42 +268,50 @@
|
|||
},
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"out" : "0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"post" : {
|
||||
"0000000000000000000000000000000000000000" : {
|
||||
"balance" : "0x00",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0186a0",
|
||||
"code" : "0x6000357c0100000000000000000000000000000000000000000000000000000000900480633e0bca3b1461003a578063c04062261461004c57005b610042610099565b8060005260206000f35b61005461005e565b8060005260206000f35b6000610068610099565b600060006101000a81548160ff02191690830217905550600060009054906101000a900460ff169050610096565b90565b60006000600060019250825060018273ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f16100fd57005b505060005163ffffffff1614156101135761011c565b60009250610194565b60028173ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f161017457005b505060005163ffffffff16141561018a57610193565b60009250610194565b5b50509056",
|
||||
"nonce" : "0x00",
|
||||
"code" : "0x7c010000000000000000000000000000000000000000000000000000000060003504633e0bca3b8114610039578063c0406226146100a857005b6100b55b600160008060456101ec8339604560006000f091508173ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f161011957005b6100bf60006100c961003d565b8060005260206000f35b8060005260206000f35b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016919091179081905560ff16919050565b505060005163ffffffff166002141561019d575b5b505090565b505060005163ffffffff1660011415610194575b60456101a7600039604560006000f090508073ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f16100ff57005b60009250610114565b600092506101145600603980600c6000396000f3007c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60026000818152602090f3603980600c6000396000f3007c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60016000818152602090f3",
|
||||
"nonce" : "0x02",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
},
|
||||
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
|
||||
"balance" : "0xca69",
|
||||
"balance" : "0x01f758",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
|
||||
"balance" : "0x02fa2617",
|
||||
"balance" : "0x02f8f928",
|
||||
"code" : "0x",
|
||||
"nonce" : "0x01",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"b88de88b35ecbf3c141e3caae2baf35834d18f63" : {
|
||||
"balance" : "0x00",
|
||||
"code" : "0x7c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60026000818152602090f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "ed06b00015d227623175bd12a5d960281781493ea1d9fed79d6c40a20e2c6ef7",
|
||||
"d2571607e241ecf590ed94b12d87c94babe36db6" : {
|
||||
"balance" : "0x00",
|
||||
"code" : "0x7c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60016000818152602090f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"postStateRoot" : "e7f84d674881d1cfd115be59e3e390271435c0b3474a482f7add54c3fe429d85",
|
||||
"pre" : {
|
||||
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
|
||||
"balance" : "0x0186a0",
|
||||
"code" : "0x6000357c0100000000000000000000000000000000000000000000000000000000900480633e0bca3b1461003a578063c04062261461004c57005b610042610099565b8060005260206000f35b61005461005e565b8060005260206000f35b6000610068610099565b600060006101000a81548160ff02191690830217905550600060009054906101000a900460ff169050610096565b90565b60006000600060019250825060018273ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f16100fd57005b505060005163ffffffff1614156101135761011c565b60009250610194565b60028173ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f161017457005b505060005163ffffffff16141561018a57610193565b60009250610194565b5b50509056",
|
||||
"code" : "0x7c010000000000000000000000000000000000000000000000000000000060003504633e0bca3b8114610039578063c0406226146100a857005b6100b55b600160008060456101ec8339604560006000f091508173ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f161011957005b6100bf60006100c961003d565b8060005260206000f35b8060005260206000f35b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016919091179081905560ff16919050565b505060005163ffffffff166002141561019d575b5b505090565b505060005163ffffffff1660011415610194575b60456101a7600039604560006000f090508073ffffffffffffffffffffffffffffffffffffffff166381bda09b60206000827c010000000000000000000000000000000000000000000000000000000002600052600460006000866161da5a03f16100ff57005b60009250610114565b600092506101145600603980600c6000396000f3007c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60026000818152602090f3603980600c6000396000f3007c0100000000000000000000000000000000000000000000000000000000600035046381bda09b8114602d57005b60016000818152602090f3",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,6 +356,8 @@
|
|||
}
|
||||
},
|
||||
"addmod1_overflow3" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -369,11 +371,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60056001600160000308600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef406",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60056001600160000308600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -385,6 +401,8 @@
|
|||
}
|
||||
},
|
||||
"addmod1_overflow4" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -398,11 +416,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60056002600160000308600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef406",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60056002600160000308600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x02"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -414,6 +446,8 @@
|
|||
}
|
||||
},
|
||||
"addmod1_overflowDiff" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -427,11 +461,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60056002600003600160000308600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef400",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60056002600003600160000308600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x04"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -842,6 +890,51 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"addmodDivByZero3" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60016000600060000803600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013866",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000600060000803600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000600060000803600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"arith1" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
@ -1152,6 +1245,51 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"divByZero_2" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60076000600d0401600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x01386c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60076000600d0401600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x07"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60076000600d0401600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"exp0" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
@ -5498,6 +5636,51 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"modByZero" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x6001600060030603600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x01386c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6001600060030603600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x6001600060030603600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mul0" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
@ -6017,6 +6200,8 @@
|
|||
}
|
||||
},
|
||||
"mulmod1_overflow2" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -6030,11 +6215,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600560027f800000000000000000000000000000000000000000000000000000000000000009600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef40c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600560027f800000000000000000000000000000000000000000000000000000000000000009600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -6046,6 +6245,8 @@
|
|||
}
|
||||
},
|
||||
"mulmod1_overflow3" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -6059,11 +6260,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600560027f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff09600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef40c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600560027f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff09600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x04"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -6075,6 +6290,8 @@
|
|||
}
|
||||
},
|
||||
"mulmod1_overflow4" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -6088,11 +6305,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600560027f800000000000000000000000000000000000000000000000000000000000000109600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0f4240",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0ef40c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600560027f800000000000000000000000000000000000000000000000000000000000000109600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x03"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -6502,6 +6733,51 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mulmoddivByZero3" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60006000600009600103600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013866",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60006000600009600103600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60006000600009600103600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"not1" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
@ -7081,6 +7357,51 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"sdivByZero2" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600160007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf923bdff6000030501600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013866",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600160007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf923bdff6000030501600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600160007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf923bdff6000030501600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sdiv_dejavu" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
@ -8109,6 +8430,8 @@
|
|||
}
|
||||
},
|
||||
"smod6" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
|
|
@ -8122,11 +8445,25 @@
|
|||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60000307600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x2710",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x01386c",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60000307600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0x01"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
|
@ -8181,6 +8518,140 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"smod8_byZero" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600d600060c86000030703600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013866",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600d600060c86000030703600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600d600060c86000030703600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"smod_i256min1" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x60016000037f800000000000000000000000000000000000000000000000000000000000000060000307600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x0172fe",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000037f800000000000000000000000000000000000000000000000000000000000000060000307600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x60016000037f800000000000000000000000000000000000000000000000000000000000000060000307600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"smod_i256min2" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
"env" : {
|
||||
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty" : "0x0100",
|
||||
"currentGasLimit" : "0x0f4240",
|
||||
"currentNumber" : "0x00",
|
||||
"currentTimestamp" : "0x01",
|
||||
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
|
||||
},
|
||||
"exec" : {
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"code" : "0x600160016000037f80000000000000000000000000000000000000000000000000000000000000006000030703600055",
|
||||
"data" : "0x",
|
||||
"gas" : "0x0186a0",
|
||||
"gasPrice" : "0x5af3107a4000",
|
||||
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013860",
|
||||
"logs" : [
|
||||
],
|
||||
"out" : "0x",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600160016000037f80000000000000000000000000000000000000000000000000000000000000006000030703600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
"0x00" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
"code" : "0x600160016000037f80000000000000000000000000000000000000000000000000000000000000006000030703600055",
|
||||
"nonce" : "0x00",
|
||||
"storage" : {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"stop" : {
|
||||
"callcreates" : [
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package vm
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
|
@ -87,7 +87,7 @@ func RunVmTest(p string, t *testing.T) {
|
|||
vm.Debug = true
|
||||
glog.SetV(4)
|
||||
glog.SetToStderr(true)
|
||||
if name != "stackLimitPush32_1024" {
|
||||
if name != "Call50000_sha256" {
|
||||
continue
|
||||
}
|
||||
*/
|
||||
|
|
@ -128,10 +128,16 @@ func RunVmTest(p string, t *testing.T) {
|
|||
ret, logs, gas, err = helper.RunState(statedb, env, test.Transaction)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// the memory required for these tests (4294967297 bytes) would take too much time.
|
||||
// on 19 May 2015 decided to skip these tests their output.
|
||||
case "mload32bitBound_return", "mload32bitBound_return2":
|
||||
default:
|
||||
rexp := helper.FromHex(test.Out)
|
||||
if bytes.Compare(rexp, ret) != 0 {
|
||||
t.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
|
||||
}
|
||||
}
|
||||
|
||||
if isVmTest {
|
||||
if len(test.Gas) == 0 && err == nil {
|
||||
|
|
@ -246,8 +252,7 @@ func TestLogTest(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPerformance(t *testing.T) {
|
||||
t.Skip()
|
||||
const fn = "../files/VMTests/vmPerformance.json"
|
||||
const fn = "../files/VMTests/vmPerformanceTest.json"
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
|
|
@ -281,13 +286,13 @@ func TestInputLimitsLight(t *testing.T) {
|
|||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
func TestStateExample(t *testing.T) {
|
||||
const fn = "../files/StateTests/stExample.json"
|
||||
func TestStateSystemOperations(t *testing.T) {
|
||||
const fn = "../files/StateTests/stSystemOperationsTest.json"
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
func TestStateSystemOperations(t *testing.T) {
|
||||
const fn = "../files/StateTests/stSystemOperationsTest.json"
|
||||
func TestStateExample(t *testing.T) {
|
||||
const fn = "../files/StateTests/stExample.json"
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
|
|
@ -342,13 +347,17 @@ func TestMemory(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMemoryStress(t *testing.T) {
|
||||
t.Skip("Skipped due to...consuming too much memory :D")
|
||||
if os.Getenv("TEST_VM_COMPLEX") == "" {
|
||||
t.Skip()
|
||||
}
|
||||
const fn = "../files/StateTests/stMemoryStressTest.json"
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
func TestQuadraticComplexity(t *testing.T) {
|
||||
t.Skip() // takes too long
|
||||
if os.Getenv("TEST_VM_COMPLEX") == "" {
|
||||
t.Skip()
|
||||
}
|
||||
const fn = "../files/StateTests/stQuadraticComplexityTest.json"
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
|
|
@ -363,21 +372,16 @@ func TestWallet(t *testing.T) {
|
|||
RunVmTest(fn, t)
|
||||
}
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
// TODO: fix JSON EOF bug and unskip
|
||||
t.Skip()
|
||||
fileNames := make([]string, 1024)
|
||||
fileInfos, err := ioutil.ReadDir("../files/StateTests/RandomTests")
|
||||
if err != nil {
|
||||
t.Errorf("Could not read StateTests/RandomTests dir: %v", err)
|
||||
return
|
||||
func TestStateTestsRandom(t *testing.T) {
|
||||
fns, _ := filepath.Glob("../files/StateTests/RandomTests/*")
|
||||
for _, fn := range fns {
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVMRandom(t *testing.T) {
|
||||
fns, _ := filepath.Glob("../files/VMTests/RandomTests/*")
|
||||
for _, fn := range fns {
|
||||
RunVmTest(fn, t)
|
||||
}
|
||||
for _, fileInfo := range fileInfos {
|
||||
fileNames = append(fileNames, fileInfo.Name())
|
||||
}
|
||||
|
||||
//for _, f := range fileNames {
|
||||
path := filepath.Join("../files/StateTests/RandomTests/", fileNames[0])
|
||||
RunVmTest(path, t)
|
||||
//}
|
||||
}
|
||||
|
|
|
|||
59
xeth/xeth.go
59
xeth/xeth.go
|
|
@ -28,6 +28,7 @@ var (
|
|||
filterTickerTime = 5 * time.Minute
|
||||
defaultGasPrice = big.NewInt(10000000000000) //150000000000
|
||||
defaultGas = big.NewInt(90000) //500000
|
||||
dappStorePre = []byte("dapp-")
|
||||
)
|
||||
|
||||
// byte will be inferred
|
||||
|
|
@ -66,12 +67,16 @@ type XEth struct {
|
|||
// regmut sync.Mutex
|
||||
// register map[string][]*interface{} // TODO improve return type
|
||||
|
||||
solcPath string
|
||||
solc *compiler.Solidity
|
||||
|
||||
agent *miner.RemoteAgent
|
||||
}
|
||||
|
||||
func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth {
|
||||
return &XEth{
|
||||
backend: eth,
|
||||
frontend: frontend,
|
||||
}
|
||||
}
|
||||
|
||||
// New creates an XEth that uses the given frontend.
|
||||
// If a nil Frontend is provided, a default frontend which
|
||||
// confirms all transactions will be used.
|
||||
|
|
@ -304,6 +309,8 @@ func (self *XEth) EthBlockByHash(strHash string) *types.Block {
|
|||
}
|
||||
|
||||
func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) {
|
||||
// Due to increasing return params and need to determine if this is from transaction pool or
|
||||
// some chain, this probably needs to be refactored for more expressiveness
|
||||
data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
|
||||
if len(data) != 0 {
|
||||
tx = types.NewTransactionFromBytes(data)
|
||||
|
|
@ -348,6 +355,24 @@ func (self *XEth) CurrentBlock() *types.Block {
|
|||
return self.backend.ChainManager().CurrentBlock()
|
||||
}
|
||||
|
||||
func (self *XEth) GetBlockReceipts(bhash common.Hash) (receipts types.Receipts, err error) {
|
||||
return self.backend.BlockProcessor().GetBlockReceipts(bhash)
|
||||
}
|
||||
|
||||
func (self *XEth) GetTxReceipt(txhash common.Hash) (receipt *types.Receipt, err error) {
|
||||
_, bhash, _, txi := self.EthTransactionByHash(common.ToHex(txhash[:]))
|
||||
var receipts types.Receipts
|
||||
receipts, err = self.backend.BlockProcessor().GetBlockReceipts(bhash)
|
||||
if err == nil {
|
||||
if txi < uint64(len(receipts)) {
|
||||
receipt = receipts[txi]
|
||||
} else {
|
||||
err = fmt.Errorf("Invalid tx index")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *XEth) GasLimit() *big.Int {
|
||||
return self.backend.ChainManager().GasLimit()
|
||||
}
|
||||
|
|
@ -357,7 +382,7 @@ func (self *XEth) Block(v interface{}) *Block {
|
|||
return self.BlockByNumber(int64(n))
|
||||
} else if str, ok := v.(string); ok {
|
||||
return self.BlockByHash(str)
|
||||
} else if f, ok := v.(float64); ok { // Don't ask ...
|
||||
} else if f, ok := v.(float64); ok { // JSON numbers are represented as float64
|
||||
return self.BlockByNumber(int64(f))
|
||||
}
|
||||
|
||||
|
|
@ -377,27 +402,24 @@ func (self *XEth) Accounts() []string {
|
|||
// accessor for solidity compiler.
|
||||
// memoized if available, retried on-demand if not
|
||||
func (self *XEth) Solc() (*compiler.Solidity, error) {
|
||||
var err error
|
||||
if self.solc == nil {
|
||||
self.solc, err = compiler.New(self.solcPath)
|
||||
}
|
||||
return self.solc, err
|
||||
return self.backend.Solc()
|
||||
}
|
||||
|
||||
// set in js console via admin interface or wrapper from cli flags
|
||||
func (self *XEth) SetSolc(solcPath string) (*compiler.Solidity, error) {
|
||||
self.solcPath = solcPath
|
||||
self.solc = nil
|
||||
self.backend.SetSolc(solcPath)
|
||||
return self.Solc()
|
||||
}
|
||||
|
||||
// store DApp value in extra database
|
||||
func (self *XEth) DbPut(key, val []byte) bool {
|
||||
self.backend.ExtraDb().Put(key, val)
|
||||
self.backend.ExtraDb().Put(append(dappStorePre, key...), val)
|
||||
return true
|
||||
}
|
||||
|
||||
// retrieve DApp value from extra database
|
||||
func (self *XEth) DbGet(key []byte) ([]byte, error) {
|
||||
val, err := self.backend.ExtraDb().Get(key)
|
||||
val, err := self.backend.ExtraDb().Get(append(dappStorePre, key...))
|
||||
return val, err
|
||||
}
|
||||
|
||||
|
|
@ -778,7 +800,7 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
|
|||
}
|
||||
|
||||
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) {
|
||||
statedb := self.State().State().Copy() //self.eth.ChainManager().TransState()
|
||||
statedb := self.State().State().Copy()
|
||||
var from *state.StateObject
|
||||
if len(fromStr) == 0 {
|
||||
accounts, err := self.backend.AccountManager().Accounts()
|
||||
|
|
@ -862,13 +884,14 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
|
|||
var (
|
||||
from = common.HexToAddress(fromStr)
|
||||
to = common.HexToAddress(toStr)
|
||||
value = common.NewValue(valueStr)
|
||||
value = common.Big(valueStr)
|
||||
gas = common.Big(gasStr)
|
||||
price = common.Big(gasPriceStr)
|
||||
data []byte
|
||||
contractCreation bool
|
||||
)
|
||||
|
||||
// 2015-05-18 Is this still needed?
|
||||
// TODO if no_private_key then
|
||||
//if _, exists := p.register[args.From]; exists {
|
||||
// p.register[args.From] = append(p.register[args.From], args)
|
||||
|
|
@ -908,9 +931,9 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
|
|||
|
||||
var tx *types.Transaction
|
||||
if contractCreation {
|
||||
tx = types.NewContractCreationTx(value.BigInt(), gas, price, data)
|
||||
tx = types.NewContractCreationTx(value, gas, price, data)
|
||||
} else {
|
||||
tx = types.NewTransactionMessage(to, value.BigInt(), gas, price, data)
|
||||
tx = types.NewTransactionMessage(to, value, gas, price, data)
|
||||
}
|
||||
|
||||
state := self.backend.ChainManager().TxState()
|
||||
|
|
@ -924,9 +947,11 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
|
|||
tx.SetNonce(nonce)
|
||||
|
||||
if err := self.sign(tx, from, false); err != nil {
|
||||
state.RemoveNonce(from, tx.Nonce())
|
||||
return "", err
|
||||
}
|
||||
if err := self.backend.TxPool().Add(tx); err != nil {
|
||||
state.RemoveNonce(from, tx.Nonce())
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue