Merge branch 'rpcfrontier' into develop

This commit is contained in:
obscuren 2015-03-11 17:37:17 +01:00
commit 239e17de12
19 changed files with 3229 additions and 1930 deletions

View File

@ -26,6 +26,7 @@ import (
"os" "os"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
@ -112,6 +113,7 @@ runtime will execute the file and exit.
}, },
} }
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
utils.UnlockedAccountFlag,
utils.BootnodesFlag, utils.BootnodesFlag,
utils.DataDirFlag, utils.DataDirFlag,
utils.ListenPortFlag, utils.ListenPortFlag,
@ -191,6 +193,21 @@ Please run 'ethereum account new' to create a new account.`)
func startEth(ctx *cli.Context, eth *eth.Ethereum) { func startEth(ctx *cli.Context, eth *eth.Ethereum) {
utils.StartEthereum(eth) utils.StartEthereum(eth)
// Load startup keys. XXX we are going to need a different format
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
if len(account) > 0 {
split := strings.Split(account, ":")
if len(split) != 2 {
utils.Fatalf("Illegal 'unlock' format (address:password)")
}
am := eth.AccountManager()
// Attempt to unlock the account
err := am.Unlock(ethutil.Hex2Bytes(split[0]), split[1])
if err != nil {
utils.Fatalf("Unlock account failed '%v'", err)
}
}
// Start auxiliary services if enabled. // Start auxiliary services if enabled.
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
utils.StartRPC(eth, ctx) utils.StartRPC(eth, ctx)

View File

@ -35,7 +35,7 @@
var web3 = require('web3'); var web3 = require('web3');
var eth = web3.eth; var eth = web3.eth;
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545')); web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var desc = [{ var desc = [{
"name": "balance(address)", "name": "balance(address)",
"type": "function", "type": "function",
@ -72,12 +72,13 @@
// deploy if not exist // deploy if not exist
if (address == null) { if (address == null) {
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056"; var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.transact({data: code}); address = web3.eth.transact({from: eth.coinbase, data: code});
localStorage.setItem("address", address); localStorage.setItem("address", address);
} }
document.querySelector("#contract_addr").innerHTML = address; document.querySelector("#contract_addr").innerHTML = address;
var contract = web3.eth.contract(address, desc); var Contract = web3.eth.contract(desc);
contract = new Contract(address);
contract.Changed({from: eth.coinbase}).changed(function() { contract.Changed({from: eth.coinbase}).changed(function() {
refresh(); refresh();
}); });
@ -88,7 +89,7 @@
var table = document.querySelector("#table_body"); var table = document.querySelector("#table_body");
table.innerHTML = ""; // clear table.innerHTML = ""; // clear
var storage = eth.storageAt(address); var storage = eth.getStorage(address);
table.innerHTML = ""; table.innerHTML = "";
for( var item in storage ) { for( var item in storage ) {
table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>"; table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>";

File diff suppressed because it is too large Load Diff

View File

@ -77,6 +77,10 @@ var (
Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM", Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM",
} }
*/ */
UnlockedAccountFlag = cli.StringFlag{
Name: "unlock",
Usage: "Unlock a given account untill this programs exits (address:password)",
}
VMDebugFlag = cli.BoolFlag{ VMDebugFlag = cli.BoolFlag{
Name: "vmdebug", Name: "vmdebug",
Usage: "Virtual Machine debug output", Usage: "Virtual Machine debug output",
@ -221,7 +225,8 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.D
func GetAccountManager(ctx *cli.Context) *accounts.Manager { func GetAccountManager(ctx *cli.Context) *accounts.Manager {
dataDir := ctx.GlobalString(DataDirFlag.Name) dataDir := ctx.GlobalString(DataDirFlag.Name)
ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys")) ks := crypto.NewKeyStorePassphrase(path.Join(dataDir, "keys"))
return accounts.NewManager(ks) km := accounts.NewManager(ks)
return km
} }
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) { func StartRPC(eth *eth.Ethereum, ctx *cli.Context) {

View File

@ -80,7 +80,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
cb := statedb.GetStateObject(coinbase.Address()) cb := statedb.GetStateObject(coinbase.Address())
st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb) st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb)
_, err := st.TransitionState() _, err := st.TransitionState()
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) { if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
return nil, nil, err return nil, nil, err
} }
@ -120,17 +120,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
for _, tx := range txs { for _, tx := range txs {
receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess) receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
return nil, nil, nil, nil, err
}
if err != nil { if err != nil {
switch { statelogger.Infoln("TX err:", err)
case IsNonceErr(err):
return nil, nil, nil, nil, err
case state.IsGasLimitErr(err):
return nil, nil, nil, nil, err
default:
statelogger.Infoln(err)
erroneous = append(erroneous, tx)
err = nil
}
} }
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
handled = append(handled, tx) handled = append(handled, tx)

View File

@ -440,12 +440,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td) self.setTotalDifficulty(td)
self.insert(block) self.insert(block)
/* XXX crashes
jsonlogger.LogJson(&logger.EthChainNewHead{ jsonlogger.LogJson(&logger.EthChainNewHead{
BlockHash: ethutil.Bytes2Hex(block.Hash()), BlockHash: ethutil.Bytes2Hex(block.Hash()),
BlockNumber: block.Number(), BlockNumber: block.Number(),
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()), ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()), BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
}) })
*/
self.setTransState(state.New(block.Root(), self.stateDb)) self.setTransState(state.New(block.Root(), self.stateDb))
queue[i] = ChainEvent{block} queue[i] = ChainEvent{block}

View File

@ -184,6 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
} }
} }
if err = self.UseGas(big.NewInt(dgas)); err != nil { if err = self.UseGas(big.NewInt(dgas)); err != nil {
println("2")
return nil, InvalidTxError(err) return nil, InvalidTxError(err)
} }
@ -198,48 +199,18 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
dataGas.Mul(dataGas, vm.GasCreateByte) dataGas.Mul(dataGas, vm.GasCreateByte)
if err := self.UseGas(dataGas); err == nil { if err := self.UseGas(dataGas); err == nil {
ref.SetCode(ret) ref.SetCode(ret)
} else {
statelogger.Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
} }
} }
/*
if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
statelogger.Infof("CREATE: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
// re-run using the JIT (validation for the JIT)
goodState := vmenv.State().Copy()
vmenv.state = stateCopy
vmenv.SetVmType(vm.JitVmTy)
vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
self.state.Set(goodState)
}
*/
} else { } else {
ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
/*
if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
statelogger.Infof("CALL: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
// re-run using the JIT (validation for the JIT)
goodState := vmenv.State().Copy()
vmenv.state = stateCopy
vmenv.SetVmType(vm.JitVmTy)
vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
self.state.Set(goodState)
}
*/
} }
if err != nil && IsValueTransferErr(err) { if err != nil && IsValueTransferErr(err) {
return nil, InvalidTxError(err) return nil, InvalidTxError(err)
} }
/*
if err != nil {
self.UseGas(self.gas)
}
*/
return return
} }

View File

@ -58,7 +58,7 @@ type JSEthereum struct {
func (self *JSEthereum) Block(v interface{}) otto.Value { func (self *JSEthereum) Block(v interface{}) otto.Value {
if number, ok := v.(int64); ok { if number, ok := v.(int64); ok {
return self.toVal(&JSBlock{self.XEth.BlockByNumber(int32(number)), self}) return self.toVal(&JSBlock{self.XEth.BlockByNumber(number), self})
} else if hash, ok := v.(string); ok { } else if hash, ok := v.(string); ok {
return self.toVal(&JSBlock{self.XEth.BlockByHash(hash), self}) return self.toVal(&JSBlock{self.XEth.BlockByHash(hash), self})
} }

View File

@ -209,6 +209,8 @@ gasLimit:
err := self.commitTransaction(tx) err := self.commitTransaction(tx)
switch { switch {
case core.IsNonceErr(err): case core.IsNonceErr(err):
fallthrough
case core.IsInvalidTxErr(err):
// Remove invalid transactions // Remove invalid transactions
remove = append(remove, tx) remove = append(remove, tx)
case state.IsGasLimitErr(err): case state.IsGasLimitErr(err):
@ -222,7 +224,7 @@ gasLimit:
} }
self.eth.TxPool().RemoveSet(remove) self.eth.TxPool().RemoveSet(remove)
self.current.coinbase.AddBalance(core.BlockReward) self.current.state.AddBalance(self.coinbase, core.BlockReward)
self.current.state.Update(ethutil.Big0) self.current.state.Update(ethutil.Big0)
self.push() self.push()
@ -258,9 +260,11 @@ func (self *worker) commitUncle(uncle *types.Header) error {
} }
func (self *worker) commitTransaction(tx *types.Transaction) error { func (self *worker) commitTransaction(tx *types.Transaction) error {
snap := self.current.state.Copy()
//fmt.Printf("proc %x %v\n", tx.Hash()[:3], tx.Nonce()) //fmt.Printf("proc %x %v\n", tx.Hash()[:3], tx.Nonce())
receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true) receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err)) { if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
self.current.state.Set(snap)
return err return err
} }

View File

@ -1,14 +1,8 @@
/*
For each request type, define the following:
1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct
3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON
*/
package rpc package rpc
import ( import (
"encoding/json"
"fmt"
"math/big" "math/big"
"path" "path"
"strings" "strings"
@ -27,8 +21,8 @@ import (
) )
var ( var (
defaultGasPrice = big.NewInt(10000000000000) defaultGasPrice = big.NewInt(150000000000)
defaultGas = big.NewInt(10000) defaultGas = big.NewInt(500000)
filterTickerTime = 15 * time.Second filterTickerTime = 15 * time.Second
) )
@ -50,21 +44,18 @@ type EthereumApi struct {
register map[string][]*NewTxArgs register map[string][]*NewTxArgs
db ethutil.Database db ethutil.Database
defaultBlockAge int64
} }
func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi { func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps")) db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
api := &EthereumApi{ api := &EthereumApi{
eth: eth, eth: eth,
mux: eth.Backend().EventMux(), mux: eth.Backend().EventMux(),
quit: make(chan struct{}), quit: make(chan struct{}),
filterManager: filter.NewFilterManager(eth.Backend().EventMux()), filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
logs: make(map[int]*logFilter), logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter), messages: make(map[int]*whisperFilter),
db: db, db: db,
defaultBlockAge: -1,
} }
go api.filterManager.Start() go api.filterManager.Start()
go api.start() go api.start()
@ -72,36 +63,33 @@ func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
return api return api
} }
func (self *EthereumApi) setStateByBlockNumber(num int64) { func (self *EthereumApi) xethWithStateNum(num int64) *xeth.XEth {
chain := self.xeth().Backend().ChainManager() chain := self.xeth().Backend().ChainManager()
var block *types.Block var block *types.Block
if self.defaultBlockAge < 0 { if num < 0 {
num = chain.CurrentBlock().Number().Int64() + num + 1 num = chain.CurrentBlock().Number().Int64() + num + 1
} }
block = chain.GetBlockByNumber(uint64(num)) block = chain.GetBlockByNumber(uint64(num))
var st *state.StateDB
if block != nil { if block != nil {
self.useState(state.New(block.Root(), self.xeth().Backend().StateDb())) st = state.New(block.Root(), self.xeth().Backend().StateDb())
} else { } else {
self.useState(chain.State()) st = chain.State()
} }
return self.xeth().WithState(st)
}
func (self *EthereumApi) getStateWithNum(num int64) *xeth.State {
return self.xethWithStateNum(num).State()
} }
func (self *EthereumApi) start() { func (self *EthereumApi) start() {
timer := time.NewTicker(filterTickerTime) timer := time.NewTicker(filterTickerTime)
events := self.mux.Subscribe(core.ChainEvent{})
done: done:
for { for {
select { select {
case ev := <-events.Chan():
switch ev.(type) {
case core.ChainEvent:
if self.defaultBlockAge < 0 {
self.setStateByBlockNumber(self.defaultBlockAge)
}
}
case <-timer.C: case <-timer.C:
self.logMut.Lock() self.logMut.Lock()
self.messagesMut.Lock() self.messagesMut.Lock()
@ -130,35 +118,35 @@ func (self *EthereumApi) stop() {
close(self.quit) close(self.quit)
} }
func (self *EthereumApi) Register(args string, reply *interface{}) error { // func (self *EthereumApi) Register(args string, reply *interface{}) error {
self.regmut.Lock() // self.regmut.Lock()
defer self.regmut.Unlock() // defer self.regmut.Unlock()
if _, ok := self.register[args]; ok { // if _, ok := self.register[args]; ok {
self.register[args] = nil // register with empty // self.register[args] = nil // register with empty
} // }
return nil // return nil
} // }
func (self *EthereumApi) Unregister(args string, reply *interface{}) error { // func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
self.regmut.Lock() // self.regmut.Lock()
defer self.regmut.Unlock() // defer self.regmut.Unlock()
delete(self.register, args) // delete(self.register, args)
return nil // return nil
} // }
func (self *EthereumApi) WatchTx(args string, reply *interface{}) error { // func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
self.regmut.Lock() // self.regmut.Lock()
defer self.regmut.Unlock() // defer self.regmut.Unlock()
txs := self.register[args] // txs := self.register[args]
self.register[args] = nil // self.register[args] = nil
*reply = txs // *reply = txs
return nil // return nil
} // }
func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error { func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
var id int var id int
@ -173,7 +161,7 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro
id = self.filterManager.InstallFilter(filter) id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()} self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id *reply = i2hex(id)
return nil return nil
} }
@ -203,7 +191,7 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
id = self.filterManager.InstallFilter(filter) id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()} self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id *reply = i2hex(id)
return nil return nil
} }
@ -240,35 +228,49 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error
return nil return nil
} }
func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) (err error) {
// This seems a bit precarious Maybe worth splitting to discrete functions // TODO if no_private_key then
if len(args.Hash) > 0 { //if _, exists := p.register[args.From]; exists {
*reply = p.xeth().BlockByHash(args.Hash) // p.register[args.From] = append(p.register[args.From], args)
} else { //} else {
*reply = p.xeth().BlockByNumber(args.BlockNumber) /*
} account := accounts.Get(fromHex(args.From))
return nil if account != nil {
} if account.Unlocked() {
if !unlockAccount(account) {
return
}
}
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { result, _ := account.Transact(fromHex(args.To), fromHex(args.Value), fromHex(args.Gas), fromHex(args.GasPrice), fromHex(args.Data))
if len(result) > 0 {
*reply = toHex(result)
}
} else if _, exists := p.register[args.From]; exists {
p.register[ags.From] = append(p.register[args.From], args)
}
*/
// TODO: align default values to have the same type, e.g. not depend on // TODO: align default values to have the same type, e.g. not depend on
// ethutil.Value conversions later on // ethutil.Value conversions later on
if ethutil.Big(args.Gas).Cmp(big.NewInt(0)) == 0 { if args.Gas.Cmp(big.NewInt(0)) == 0 {
args.Gas = defaultGas.String() args.Gas = defaultGas
} }
if ethutil.Big(args.GasPrice).Cmp(big.NewInt(0)) == 0 { if args.GasPrice.Cmp(big.NewInt(0)) == 0 {
args.GasPrice = defaultGasPrice.String() args.GasPrice = defaultGasPrice
} }
result, _ := p.xeth().Transact(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data) *reply, err = p.xeth().Transact(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
*reply = result if err != nil {
fmt.Println("err:", err)
return err
}
return nil return nil
} }
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error { func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
result, err := p.xeth().Call(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data) result, err := p.xethWithStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
if err != nil { if err != nil {
return err return err
} }
@ -277,23 +279,28 @@ func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
return nil return nil
} }
func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { func (p *EthereumApi) GetBalance(args *GetBalanceArgs, reply *interface{}) error {
err := args.requirementsPushTx() if err := args.requirements(); err != nil {
if err != nil {
return err return err
} }
result, _ := p.xeth().PushTx(args.Tx) state := p.getStateWithNum(args.BlockNumber).SafeGet(args.Address)
*reply = result *reply = toHex(state.Balance().Bytes())
return nil return nil
} }
func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error { func (p *EthereumApi) GetStorage(args *GetStorageArgs, reply *interface{}) error {
err := args.requirements() if err := args.requirements(); err != nil {
if err != nil {
return err return err
} }
*reply = p.getStateWithNum(args.BlockNumber).SafeGet(args.Address).Storage()
return nil
}
state := p.xeth().State().SafeGet(args.Address) func (p *EthereumApi) GetStorageAt(args *GetStorageAtArgs, reply *interface{}) error {
if err := args.requirements(); err != nil {
return err
}
state := p.getStateWithNum(args.BlockNumber).SafeGet(args.Address)
value := state.StorageString(args.Key) value := state.StorageString(args.Key)
var hx string var hx string
@ -309,115 +316,31 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
return nil return nil
} }
func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
*reply = p.xeth().State().SafeGet(args.Address).Storage()
return nil
}
func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
*reply = p.xeth().PeerCount()
return nil
}
func (p *EthereumApi) GetIsListening(reply *interface{}) error {
*reply = p.xeth().IsListening()
return nil
}
func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
*reply = p.xeth().Coinbase()
return nil
}
func (p *EthereumApi) Accounts(reply *interface{}) error {
*reply = p.xeth().Accounts()
return nil
}
func (p *EthereumApi) GetIsMining(reply *interface{}) error {
*reply = p.xeth().IsMining()
return nil
}
func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error {
*reply = p.xeth().SetMining(shouldmine)
return nil
}
func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error {
*reply = p.defaultBlockAge
return nil
}
func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int64, reply *interface{}) error {
p.defaultBlockAge = defaultBlockAge
p.setStateByBlockNumber(p.defaultBlockAge)
*reply = true
return nil
}
func (p *EthereumApi) BlockNumber(reply *interface{}) error {
*reply = p.xeth().Backend().ChainManager().CurrentBlock().Number()
return nil
}
func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error { func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
err := args.requirements() err := args.requirements()
if err != nil { if err != nil {
return err return err
} }
*reply = p.xeth().TxCountAt(args.Address) *reply = p.xethWithStateNum(args.BlockNumber).TxCountAt(args.Address)
return nil return nil
} }
func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error { func (p *EthereumApi) GetData(args *GetDataArgs, reply *interface{}) error {
err := args.requirements() if err := args.requirements(); err != nil {
if err != nil {
return err return err
} }
state := p.xeth().State().SafeGet(args.Address) *reply = p.xethWithStateNum(args.BlockNumber).CodeAt(args.Address)
*reply = toHex(state.Balance().Bytes())
return nil
}
func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
*reply = p.xeth().CodeAt(args.Address)
return nil return nil
} }
func (p *EthereumApi) GetCompilers(reply *interface{}) error { func (p *EthereumApi) GetCompilers(reply *interface{}) error {
c := []string{"serpent"} c := []string{""}
*reply = c *reply = c
return nil return nil
} }
func (p *EthereumApi) CompileSerpent(script string, reply *interface{}) error {
res, err := ethutil.Compile(script, false)
if err != nil {
return err
}
*reply = res
return nil
}
func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error {
*reply = toHex(crypto.Sha3(fromHex(args.Data)))
return nil
}
func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error { func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
err := args.requirements() if err := args.requirements(); err != nil {
if err != nil {
return err return err
} }
@ -427,8 +350,7 @@ func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
} }
func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error { func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
err := args.requirements() if err := args.requirements(); err != nil {
if err != nil {
return err return err
} }
@ -442,14 +364,18 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
return nil return nil
} }
func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) error { func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
var id int var id int
args.Fn = func(msg xeth.WhisperMessage) { opts := new(xeth.Options)
opts.From = args.From
opts.To = args.To
opts.Topics = args.Topics
opts.Fn = func(msg xeth.WhisperMessage) {
p.messagesMut.Lock() p.messagesMut.Lock()
defer p.messagesMut.Unlock() defer p.messagesMut.Unlock()
p.messages[id].add(msg) // = append(p.messages[id], msg) p.messages[id].add(msg) // = append(p.messages[id], msg)
} }
id = p.xeth().Whisper().Watch(args) id = p.xeth().Whisper().Watch(opts)
p.messages[id] = &whisperFilter{timeout: time.Now()} p.messages[id] = &whisperFilter{timeout: time.Now()}
*reply = id *reply = id
return nil return nil
@ -467,7 +393,7 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error {
} }
func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error { func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error {
err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl) err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl)
if err != nil { if err != nil {
return err return err
} }
@ -486,199 +412,358 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
return nil return nil
} }
func (p *EthereumApi) GetBlockByHash(blockhash string, includetx bool) (*BlockRes, error) {
block := p.xeth().EthBlockByHash(blockhash)
br := NewBlockRes(block)
br.fullTx = includetx
return br, nil
}
func (p *EthereumApi) GetBlockByNumber(blocknum int64, includetx bool) (*BlockRes, error) {
block := p.xeth().EthBlockByNumber(blocknum)
br := NewBlockRes(block)
br.fullTx = includetx
return br, nil
}
func (p *EthereumApi) GetBlockTransactionCountByHash(blockhash string) (int64, error) {
block := p.xeth().EthBlockByHash(blockhash)
br := NewBlockRes(block)
return int64(len(br.Transactions)), nil
}
func (p *EthereumApi) GetBlockTransactionCountByNumber(blocknum int64) (int64, error) {
block := p.xeth().EthBlockByNumber(blocknum)
br := NewBlockRes(block)
return int64(len(br.Transactions)), nil
}
func (p *EthereumApi) GetBlockUncleCountByHash(blockhash string) (int64, error) {
block := p.xeth().EthBlockByHash(blockhash)
br := NewBlockRes(block)
return int64(len(br.Uncles)), nil
}
func (p *EthereumApi) GetBlockUncleCountByNumber(blocknum int64) (int64, error) {
block := p.xeth().EthBlockByNumber(blocknum)
br := NewBlockRes(block)
return int64(len(br.Uncles)), nil
}
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
rpclogger.DebugDetailf("%T %s", req.Params, req.Params) rpclogger.Debugf("%s %s", req.Method, req.Params)
switch req.Method { switch req.Method {
case "web3_sha3":
args := new(Sha3Args)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = toHex(crypto.Sha3(fromHex(args.Data)))
case "net_listening":
*reply = p.xeth().IsListening()
case "net_peerCount":
*reply = toHex(big.NewInt(int64(p.xeth().PeerCount())).Bytes())
case "eth_coinbase": case "eth_coinbase":
return p.GetCoinbase(reply) *reply = p.xeth().Coinbase()
case "eth_listening":
return p.GetIsListening(reply)
case "eth_mining": case "eth_mining":
return p.GetIsMining(reply) *reply = p.xeth().IsMining()
case "eth_setMining": case "eth_gasPrice":
args, err := req.ToBoolArgs() *reply = toHex(defaultGasPrice.Bytes())
if err != nil {
return err
}
return p.SetMining(args, reply)
case "eth_defaultBlock":
return p.GetDefaultBlockAge(reply)
case "eth_setDefaultBlock":
args, err := req.ToIntArgs()
if err != nil {
return err
}
return p.SetDefaultBlockAge(int64(args), reply)
case "eth_peerCount":
return p.GetPeerCount(reply)
case "eth_number":
return p.BlockNumber(reply)
case "eth_accounts": case "eth_accounts":
return p.Accounts(reply) *reply = p.xeth().Accounts()
case "eth_countAt": case "eth_blockNumber":
args, err := req.ToGetTxCountArgs() *reply = toHex(p.xeth().Backend().ChainManager().CurrentBlock().Number().Bytes())
if err != nil { case "eth_getBalance":
args := new(GetBalanceArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.GetTxCountAt(args, reply) return p.GetBalance(args, reply)
case "eth_codeAt": case "eth_getStorage", "eth_storageAt":
args, err := req.ToGetCodeAtArgs() args := new(GetStorageArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.GetCodeAt(args, reply) return p.GetStorage(args, reply)
case "eth_balanceAt": case "eth_getStorageAt":
args, err := req.ToGetBalanceArgs() args := new(GetStorageAtArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetBalanceAt(args, reply)
case "eth_stateAt":
args, err := req.ToGetStateArgs()
if err != nil {
return err
}
return p.GetStateAt(args, reply)
case "eth_storageAt":
args, err := req.ToStorageAtArgs()
if err != nil {
return err return err
} }
return p.GetStorageAt(args, reply) return p.GetStorageAt(args, reply)
case "eth_blockByNumber", "eth_blockByHash": case "eth_getTransactionCount":
args, err := req.ToGetBlockArgs() args := new(GetTxCountArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetTxCountAt(args, reply)
case "eth_getBlockTransactionCountByHash":
args := new(GetBlockByHashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockTransactionCountByHash(args.BlockHash)
if err != nil { if err != nil {
return err return err
} }
return p.GetBlock(args, reply) *reply = toHex(big.NewInt(v).Bytes())
case "eth_transact": case "eth_getBlockTransactionCountByNumber":
args, err := req.ToNewTxArgs() args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockTransactionCountByNumber(args.BlockNumber)
if err != nil { if err != nil {
return err return err
} }
*reply = toHex(big.NewInt(v).Bytes())
case "eth_getUncleCountByBlockHash":
args := new(GetBlockByHashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockUncleCountByHash(args.BlockHash)
if err != nil {
return err
}
*reply = toHex(big.NewInt(v).Bytes())
case "eth_getUncleCountByBlockNumber":
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockUncleCountByNumber(args.BlockNumber)
if err != nil {
return err
}
*reply = toHex(big.NewInt(v).Bytes())
case "eth_getData":
args := new(GetDataArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetData(args, reply)
case "eth_sendTransaction", "eth_transact":
args := new(NewTxArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.Transact(args, reply) return p.Transact(args, reply)
case "eth_call": case "eth_call":
args, err := req.ToNewTxArgs() args := new(NewTxArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.Call(args, reply) return p.Call(args, reply)
case "eth_newFilter": case "eth_flush":
args, err := req.ToFilterArgs() return errNotImplemented
case "eth_getBlockByHash":
args := new(GetBlockByHashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByHash(args.BlockHash, args.Transactions)
if err != nil { if err != nil {
return err return err
} }
*reply = v
case "eth_getBlockByNumber":
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByNumber(args.BlockNumber, args.Transactions)
if err != nil {
return err
}
*reply = v
case "eth_getTransactionByHash":
return errNotImplemented
case "eth_getTransactionByBlockHashAndIndex":
args := new(HashIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByHash(args.BlockHash, true)
if err != nil {
return err
}
if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
}
*reply = v.Transactions[args.Index]
case "eth_getTransactionByBlockNumberAndIndex":
args := new(BlockNumIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByNumber(args.BlockNumber, true)
if err != nil {
return err
}
if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
}
*reply = v.Transactions[args.Index]
case "eth_getUncleByBlockHashAndIndex":
args := new(HashIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByHash(args.BlockHash, false)
if err != nil {
return err
}
if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
}
uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
if err != nil {
return err
}
*reply = uncle
case "eth_getUncleByBlockNumberAndIndex":
args := new(BlockNumIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockByNumber(args.BlockNumber, true)
if err != nil {
return err
}
if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
}
uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
if err != nil {
return err
}
*reply = uncle
case "eth_getCompilers":
return p.GetCompilers(reply)
case "eth_compileSolidity":
case "eth_compileLLL":
case "eth_compileSerpent":
return errNotImplemented
case "eth_newFilter":
args := new(FilterOptions)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.NewFilter(args, reply) return p.NewFilter(args, reply)
case "eth_newFilterString": case "eth_newBlockFilter":
args, err := req.ToFilterStringArgs() args := new(FilterStringArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.NewFilterString(args, reply) return p.NewFilterString(args.Word, reply)
case "eth_uninstallFilter": case "eth_uninstallFilter":
args, err := req.ToUninstallFilterArgs() args := new(FilterIdArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.UninstallFilter(args, reply) return p.UninstallFilter(args.Id, reply)
case "eth_changed": case "eth_getFilterChanges":
args, err := req.ToIdArgs() args := new(FilterIdArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.FilterChanged(args, reply) return p.FilterChanged(args.Id, reply)
case "eth_filterLogs": case "eth_getFilterLogs":
args, err := req.ToIdArgs() args := new(FilterIdArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.Logs(args, reply) return p.Logs(args.Id, reply)
case "eth_logs": case "eth_getLogs":
args, err := req.ToFilterArgs() args := new(FilterOptions)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.AllLogs(args, reply) return p.AllLogs(args, reply)
case "eth_gasPrice": case "eth_getWork":
*reply = toHex(defaultGasPrice.Bytes()) case "eth_submitWork":
return nil return errNotImplemented
case "eth_register":
args, err := req.ToRegisterArgs()
if err != nil {
return err
}
return p.Register(args, reply)
case "eth_unregister":
args, err := req.ToRegisterArgs()
if err != nil {
return err
}
return p.Unregister(args, reply)
case "eth_watchTx":
args, err := req.ToWatchTxArgs()
if err != nil {
return err
}
return p.WatchTx(args, reply)
case "eth_compilers":
return p.GetCompilers(reply)
case "eth_serpent":
args, err := req.ToCompileArgs()
if err != nil {
return err
}
return p.CompileSerpent(args, reply)
case "web3_sha3":
args, err := req.ToSha3Args()
if err != nil {
return err
}
return p.Sha3(args, reply)
case "db_put": case "db_put":
args, err := req.ToDbPutArgs() args := new(DbArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.DbPut(args, reply) return p.DbPut(args, reply)
case "db_get": case "db_get":
args, err := req.ToDbGetArgs() args := new(DbArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.DbGet(args, reply) return p.DbGet(args, reply)
case "shh_newIdentity":
return p.NewWhisperIdentity(reply)
case "shh_newFilter":
args, err := req.ToWhisperFilterArgs()
if err != nil {
return err
}
return p.NewWhisperFilter(args, reply)
case "shh_changed":
args, err := req.ToIdArgs()
if err != nil {
return err
}
return p.MessagesChanged(args, reply)
case "shh_post": case "shh_post":
args, err := req.ToWhisperPostArgs() args := new(WhisperMessageArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.WhisperPost(args, reply) return p.WhisperPost(args, reply)
case "shh_haveIdentity": case "shh_newIdentity":
args, err := req.ToWhisperHasIdentityArgs() return p.NewWhisperIdentity(reply)
if err != nil { case "shh_hasIdentity":
args := new(WhisperIdentityArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.HasWhisperIdentity(args, reply) return p.HasWhisperIdentity(args.Identity, reply)
case "shh_newGroup":
case "shh_addToGroup":
return errNotImplemented
case "shh_newFilter":
args := new(WhisperFilterArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.NewWhisperFilter(args, reply)
case "shh_uninstallFilter":
return errNotImplemented
case "shh_getFilterChanges":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.MessagesChanged(args.Id, reply)
case "shh_getMessages": case "shh_getMessages":
args, err := req.ToIdArgs() args := new(FilterIdArgs)
if err != nil { if err := json.Unmarshal(req.Params, &args); err != nil {
return err return err
} }
return p.WhisperMessages(args, reply) return p.WhisperMessages(args.Id, reply)
// case "eth_register":
// args, err := req.ToRegisterArgs()
// if err != nil {
// return err
// }
// return p.Register(args, reply)
// case "eth_unregister":
// args, err := req.ToRegisterArgs()
// if err != nil {
// return err
// }
// return p.Unregister(args, reply)
// case "eth_watchTx":
// args, err := req.ToWatchTxArgs()
// if err != nil {
// return err
// }
// return p.WatchTx(args, reply)
default: default:
return NewErrorWithMessage(errNotImplemented, req.Method) return NewErrorWithMessage(errNotImplemented, req.Method)
} }
@ -694,9 +779,38 @@ func (self *EthereumApi) xeth() *xeth.XEth {
return self.eth return self.eth
} }
func (self *EthereumApi) useState(statedb *state.StateDB) { func toFilterOptions(options *FilterOptions) core.FilterOptions {
self.xethMu.Lock() var opts core.FilterOptions
defer self.xethMu.Unlock()
self.eth = self.eth.UseState(statedb) // Convert optional address slice/string to byte slice
if str, ok := options.Address.(string); ok {
opts.Address = [][]byte{fromHex(str)}
} else if slice, ok := options.Address.([]interface{}); ok {
bslice := make([][]byte, len(slice))
for i, addr := range slice {
if saddr, ok := addr.(string); ok {
bslice[i] = fromHex(saddr)
}
}
opts.Address = bslice
}
opts.Earliest = options.Earliest
opts.Latest = options.Latest
topics := make([][][]byte, len(options.Topics))
for i, topicDat := range options.Topics {
if slice, ok := topicDat.([]interface{}); ok {
topics[i] = make([][]byte, len(slice))
for j, topic := range slice {
topics[i][j] = fromHex(topic.(string))
}
} else if str, ok := topicDat.(string); ok {
topics[i] = make([][]byte, 1)
topics[i][0] = fromHex(str)
}
}
opts.Topics = topics
return opts
} }

View File

@ -1,11 +1,29 @@
package rpc package rpc
import ( import (
"encoding/json"
"sync" "sync"
"testing" "testing"
"time" "time"
) )
func TestWeb3Sha3(t *testing.T) {
jsonstr := `{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}`
expected := "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
api := &EthereumApi{}
var req RpcRequest
json.Unmarshal([]byte(jsonstr), &req)
var response interface{}
_ = api.GetRequestReply(&req, &response)
if response.(string) != expected {
t.Errorf("Expected %s got %s", expected, response)
}
}
func TestFilterClose(t *testing.T) { func TestFilterClose(t *testing.T) {
t.Skip() t.Skip()
api := &EthereumApi{ api := &EthereumApi{

View File

@ -1,247 +1,331 @@
package rpc package rpc
import "encoding/json" import (
"bytes"
"encoding/json"
"math/big"
import "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/ethutil"
)
type GetBlockArgs struct { func blockNumber(raw json.RawMessage, number *int64) (err error) {
BlockNumber int32 var str string
Hash string if err = json.Unmarshal(raw, &str); err != nil {
return errDecodeArgs
}
switch str {
case "latest":
*number = -1
case "pending":
*number = 0
default:
*number = ethutil.String2Big(str).Int64()
}
return nil
} }
func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { type GetBlockByHashArgs struct {
argint, argstr := int32(0), "" BlockHash string
if err = json.Unmarshal(b, &argint); err == nil { Transactions bool
obj.BlockNumber = argint }
return
func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
} }
if err = json.Unmarshal(b, &argstr); err == nil {
obj.Hash = argstr if len(obj) < 1 {
return return errArguments
} }
return errDecodeArgs
argstr, ok := obj[0].(string)
if !ok {
return errDecodeArgs
}
args.BlockHash = argstr
if len(obj) > 1 {
args.Transactions = obj[1].(bool)
}
return nil
}
type GetBlockByNumberArgs struct {
BlockNumber int64
Transactions bool
}
func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
if v, ok := obj[0].(float64); ok {
args.BlockNumber = int64(v)
} else {
args.BlockNumber = ethutil.Big(obj[0].(string)).Int64()
}
if len(obj) > 1 {
args.Transactions = obj[1].(bool)
}
return nil
} }
type NewTxArgs struct { type NewTxArgs struct {
From string `json:"from"` From string
Pass string `json:"pass"` To string
To string `json:"to"` Value *big.Int
Value string `json:"value"` Gas *big.Int
Gas string `json:"gas"` GasPrice *big.Int
GasPrice string `json:"gasPrice"` Data string
Data string `json:"data"`
BlockNumber int64
} }
func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
// Data can be either specified as "data" or "code" :-/ var obj struct{ From, To, Value, Gas, GasPrice, Data string }
var ext struct { if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
From string return err
To string
Value string
Gas string
GasPrice string
Data string
Code string
} }
if err = json.Unmarshal(b, &ext); err == nil { args.From = obj.From
if len(ext.Data) == 0 { args.To = obj.To
ext.Data = ext.Code args.Value = ethutil.Big(obj.Value)
} args.Gas = ethutil.Big(obj.Gas)
obj.From = ext.From args.GasPrice = ethutil.Big(obj.GasPrice)
obj.To = ext.To args.Data = obj.Data
obj.Value = ext.Value
obj.Gas = ext.Gas
obj.GasPrice = ext.GasPrice
obj.Data = ext.Data
return
}
return errDecodeArgs
}
type PushTxArgs struct {
Tx string `json:"tx"`
}
func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Tx = arg0
return
}
return errDecodeArgs
}
func (a *PushTxArgs) requirementsPushTx() error {
if a.Tx == "" {
return NewErrorWithMessage(errArguments, "PushTx requires a 'tx' as argument")
}
return nil return nil
} }
type GetStorageArgs struct { type GetStorageArgs struct {
Address string Address string
BlockNumber int64
} }
func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Address); err != nil { if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs return errDecodeArgs
} }
return
return nil
} }
func (a *GetStorageArgs) requirements() error { func (args *GetStorageArgs) requirements() error {
if len(a.Address) == 0 { if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "Address cannot be blank")
} }
return nil return nil
} }
type GetStateArgs struct { type GetStorageAtArgs struct {
Address string Address string
Key string Key string
BlockNumber int64
} }
func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) { func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := "" var obj []string
if err = json.Unmarshal(b, &arg0); err == nil { if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
obj.Address = arg0 return errDecodeArgs
return
} }
return errDecodeArgs if len(obj) < 2 {
return errDecodeArgs
}
args.Address = obj[0]
args.Key = obj[1]
return nil
} }
func (a *GetStateArgs) requirements() error { func (args *GetStorageAtArgs) requirements() error {
if a.Address == "" { if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "Address cannot be blank")
} }
if a.Key == "" {
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'key' value as argument") if len(args.Key) == 0 {
return NewErrorWithMessage(errArguments, "Key cannot be blank")
} }
return nil return nil
} }
type GetTxCountArgs struct { type GetTxCountArgs struct {
Address string `json:"address"` Address string
BlockNumber int64
} }
func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := "" if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
if err = json.Unmarshal(b, &arg0); err == nil { return errDecodeArgs
obj.Address = arg0
return
} }
return errDecodeArgs
return nil
} }
func (a *GetTxCountArgs) requirements() error { func (args *GetTxCountArgs) requirements() error {
if a.Address == "" { if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "Address cannot be blank")
} }
return nil return nil
} }
type GetBalanceArgs struct { type GetBalanceArgs struct {
Address string Address string
BlockNumber int64
} }
func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := "" if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
if err = json.Unmarshal(b, &arg0); err == nil { return errDecodeArgs
obj.Address = arg0
return
} }
return errDecodeArgs
return nil
} }
func (a *GetBalanceArgs) requirements() error { func (args *GetBalanceArgs) requirements() error {
if a.Address == "" { if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "Address cannot be blank")
} }
return nil return nil
} }
type GetCodeAtArgs struct { type GetDataArgs struct {
Address string Address string
BlockNumber int64
} }
func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) { func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := "" if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
if err = json.Unmarshal(b, &arg0); err == nil { return errDecodeArgs
obj.Address = arg0
return
} }
return errDecodeArgs
return nil
} }
func (a *GetCodeAtArgs) requirements() error { func (args *GetDataArgs) requirements() error {
if a.Address == "" { if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument") return NewErrorWithMessage(errArguments, "Address cannot be blank")
} }
return nil return nil
} }
type BlockNumIndexArgs struct {
BlockNumber int64
Index int64
}
type HashIndexArgs struct {
BlockHash string
Index int64
}
type Sha3Args struct { type Sha3Args struct {
Data string Data string
} }
func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Data); err != nil { var obj []interface{}
return errDecodeArgs r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return NewErrorWithMessage(errDecodeArgs, err.Error())
} }
return
if len(obj) < 1 {
return errArguments
}
args.Data = obj[0].(string)
return nil
} }
// type FilterArgs struct {
// FromBlock uint64
// ToBlock uint64
// Limit uint64
// Offset uint64
// Address string
// Topics []string
// }
// func (args *FilterArgs) UnmarshalJSON(b []byte) (err error) {
// var obj []struct {
// FromBlock string `json:"fromBlock"`
// ToBlock string `json:"toBlock"`
// Limit string `json:"limit"`
// Offset string `json:"offset"`
// Address string `json:"address"`
// Topics []string `json:"topics"`
// }
// if err = json.Unmarshal(b, &obj); err != nil {
// return errDecodeArgs
// }
// if len(obj) < 1 {
// return errArguments
// }
// args.FromBlock = uint64(ethutil.Big(obj[0].FromBlock).Int64())
// args.ToBlock = uint64(ethutil.Big(obj[0].ToBlock).Int64())
// args.Limit = uint64(ethutil.Big(obj[0].Limit).Int64())
// args.Offset = uint64(ethutil.Big(obj[0].Offset).Int64())
// args.Address = obj[0].Address
// args.Topics = obj[0].Topics
// return nil
// }
type FilterOptions struct { type FilterOptions struct {
Earliest int64 Earliest int64
Latest int64 Latest int64
Address interface{} Address interface{}
Topic []interface{} Topics []interface{}
Skip int Skip int
Max int Max int
} }
func toFilterOptions(options *FilterOptions) core.FilterOptions { func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
var opts core.FilterOptions var obj []struct {
FromBlock string `json:"fromBlock"`
// Convert optional address slice/string to byte slice ToBlock string `json:"toBlock"`
if str, ok := options.Address.(string); ok { Limit string `json:"limit"`
opts.Address = [][]byte{fromHex(str)} Offset string `json:"offset"`
} else if slice, ok := options.Address.([]interface{}); ok { Address string `json:"address"`
bslice := make([][]byte, len(slice)) Topics []interface{} `json:"topics"`
for i, addr := range slice {
if saddr, ok := addr.(string); ok {
bslice[i] = fromHex(saddr)
}
}
opts.Address = bslice
} }
opts.Earliest = options.Earliest if err = json.Unmarshal(b, &obj); err != nil {
opts.Latest = options.Latest return errDecodeArgs
topics := make([][][]byte, len(options.Topic))
for i, topicDat := range options.Topic {
if slice, ok := topicDat.([]interface{}); ok {
topics[i] = make([][]byte, len(slice))
for j, topic := range slice {
topics[i][j] = fromHex(topic.(string))
}
} else if str, ok := topicDat.(string); ok {
topics[i] = make([][]byte, 1)
topics[i][0] = fromHex(str)
}
} }
opts.Topics = topics
return opts if len(obj) < 1 {
return errArguments
}
args.Earliest = int64(ethutil.Big(obj[0].FromBlock).Int64())
args.Latest = int64(ethutil.Big(obj[0].ToBlock).Int64())
args.Max = int(ethutil.Big(obj[0].Limit).Int64())
args.Skip = int(ethutil.Big(obj[0].Offset).Int64())
args.Address = obj[0].Address
args.Topics = obj[0].Topics
return nil
} }
type FilterChangedArgs struct { // type FilterChangedArgs struct {
n int // n int
} // }
type DbArgs struct { type DbArgs struct {
Database string Database string
@ -249,12 +333,32 @@ type DbArgs struct {
Value string Value string
} }
func (args *DbArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) < 2 {
return errArguments
}
args.Database = obj[0].(string)
args.Key = obj[1].(string)
if len(obj) > 2 {
args.Value = obj[2].(string)
}
return nil
}
func (a *DbArgs) requirements() error { func (a *DbArgs) requirements() error {
if len(a.Database) == 0 { if len(a.Database) == 0 {
return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Database' value as argument") return NewErrorWithMessage(errArguments, "Database cannot be blank")
} }
if len(a.Key) == 0 { if len(a.Key) == 0 {
return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument") return NewErrorWithMessage(errArguments, "Key cannot be blank")
} }
return nil return nil
} }
@ -263,7 +367,140 @@ type WhisperMessageArgs struct {
Payload string Payload string
To string To string
From string From string
Topic []string Topics []string
Priority uint32 Priority uint32
Ttl uint32 Ttl uint32
} }
func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) {
var obj []struct {
Payload string
To string
From string
Topics []string
Priority string
Ttl string
}
if err = json.Unmarshal(b, &obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.Payload = obj[0].Payload
args.To = obj[0].To
args.From = obj[0].From
args.Topics = obj[0].Topics
args.Priority = uint32(ethutil.Big(obj[0].Priority).Int64())
args.Ttl = uint32(ethutil.Big(obj[0].Ttl).Int64())
return nil
}
type CompileArgs struct {
Source string
}
func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) > 0 {
args.Source = obj[0].(string)
}
return nil
}
type FilterStringArgs struct {
Word string
}
func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
var obj []string
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errDecodeArgs
}
args.Word = obj[0]
return nil
}
type FilterIdArgs struct {
Id int
}
func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) {
var obj []string
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errDecodeArgs
}
args.Id = int(ethutil.Big(obj[0]).Int64())
return nil
}
type WhisperIdentityArgs struct {
Identity string
}
func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) {
var obj []string
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errDecodeArgs
}
args.Identity = obj[0]
return nil
}
type WhisperFilterArgs struct {
To string `json:"to"`
From string
Topics []string
}
func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
var obj []struct {
To string
From string
Topics []string
}
if err = json.Unmarshal(b, &obj); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.To = obj[0].To
args.From = obj[0].From
args.Topics = obj[0].Topics
return nil
}

434
rpc/args_test.go Normal file
View File

@ -0,0 +1,434 @@
package rpc
import (
"bytes"
"encoding/json"
"math/big"
"testing"
)
func TestSha3(t *testing.T) {
input := `["0x68656c6c6f20776f726c64"]`
expected := "0x68656c6c6f20776f726c64"
args := new(Sha3Args)
json.Unmarshal([]byte(input), &args)
if args.Data != expected {
t.Error("got %s expected %s", input, expected)
}
}
func TestGetBalanceArgs(t *testing.T) {
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x1f"]`
expected := new(GetBalanceArgs)
expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
expected.BlockNumber = 31
args := new(GetBalanceArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if args.Address != expected.Address {
t.Errorf("Address should be %v but is %v", expected.Address, args.Address)
}
if args.BlockNumber != expected.BlockNumber {
t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber)
}
}
func TestGetBlockByHashArgs(t *testing.T) {
input := `["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true]`
expected := new(GetBlockByHashArgs)
expected.BlockHash = "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
expected.Transactions = true
args := new(GetBlockByHashArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if args.BlockHash != expected.BlockHash {
t.Errorf("BlockHash should be %v but is %v", expected.BlockHash, args.BlockHash)
}
if args.Transactions != expected.Transactions {
t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions)
}
}
func TestGetBlockByNumberArgs(t *testing.T) {
input := `["0x1b4", false]`
expected := new(GetBlockByNumberArgs)
expected.BlockNumber = 436
expected.Transactions = false
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if args.BlockNumber != expected.BlockNumber {
t.Errorf("BlockHash should be %v but is %v", expected.BlockNumber, args.BlockNumber)
}
if args.Transactions != expected.Transactions {
t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions)
}
}
func TestNewTxArgs(t *testing.T) {
input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a000",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}]`
expected := new(NewTxArgs)
expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155"
expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675"
expected.Gas = big.NewInt(30400)
expected.GasPrice = big.NewInt(10000000000000)
expected.Value = big.NewInt(10000000000000)
expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
args := new(NewTxArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.From != args.From {
t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
}
if expected.To != args.To {
t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
}
if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 {
t.Errorf("Gas shoud be %#v but is %#v", expected.Gas.Bytes(), args.Gas.Bytes())
}
if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 {
t.Errorf("GasPrice shoud be %#v but is %#v", expected.GasPrice, args.GasPrice)
}
if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 {
t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value)
}
if expected.Data != args.Data {
t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data)
}
}
func TestGetStorageArgs(t *testing.T) {
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
expected := new(GetStorageArgs)
expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
expected.BlockNumber = -1
args := new(GetStorageArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if expected.Address != args.Address {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
}
}
func TestGetStorageAtArgs(t *testing.T) {
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]`
expected := new(GetStorageAtArgs)
expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
expected.Key = "0x0"
expected.BlockNumber = 2
args := new(GetStorageAtArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if expected.Address != args.Address {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
if expected.Key != args.Key {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
}
}
func TestGetTxCountArgs(t *testing.T) {
input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
expected := new(GetTxCountArgs)
expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
expected.BlockNumber = -1
args := new(GetTxCountArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if expected.Address != args.Address {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
}
}
func TestGetDataArgs(t *testing.T) {
input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]`
expected := new(GetDataArgs)
expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
expected.BlockNumber = -1
args := new(GetDataArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if expected.Address != args.Address {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
if expected.BlockNumber != args.BlockNumber {
t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
}
}
func TestFilterOptions(t *testing.T) {
input := `[{
"fromBlock": "0x1",
"toBlock": "0x2",
"limit": "0x3",
"offset": "0x0",
"address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
"topics": ["0x12341234"]}]`
expected := new(FilterOptions)
expected.Earliest = 1
expected.Latest = 2
expected.Max = 3
expected.Skip = 0
expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
// expected.Topics = []string{"0x12341234"}
args := new(FilterOptions)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.Earliest != args.Earliest {
t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest)
}
if expected.Latest != args.Latest {
t.Errorf("Latest shoud be %#v but is %#v", expected.Latest, args.Latest)
}
if expected.Max != args.Max {
t.Errorf("Max shoud be %#v but is %#v", expected.Max, args.Max)
}
if expected.Skip != args.Skip {
t.Errorf("Skip shoud be %#v but is %#v", expected.Skip, args.Skip)
}
if expected.Address != args.Address {
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
}
// if expected.Topics != args.Topics {
// t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic)
// }
}
func TestDbArgs(t *testing.T) {
input := `["0x74657374","0x6b6579","0x6d79537472696e67"]`
expected := new(DbArgs)
expected.Database = "0x74657374"
expected.Key = "0x6b6579"
expected.Value = "0x6d79537472696e67"
args := new(DbArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if err := args.requirements(); err != nil {
t.Error(err)
}
if expected.Database != args.Database {
t.Errorf("Database shoud be %#v but is %#v", expected.Database, args.Database)
}
if expected.Key != args.Key {
t.Errorf("Key shoud be %#v but is %#v", expected.Key, args.Key)
}
if expected.Value != args.Value {
t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value)
}
}
func TestWhisperMessageArgs(t *testing.T) {
input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2",
"topics": ["0x68656c6c6f20776f726c64"],
"payload":"0x68656c6c6f20776f726c64",
"ttl": "0x64",
"priority": "0x64"}]`
expected := new(WhisperMessageArgs)
expected.From = "0xc931d93e97ab07fe42d923478ba2465f2"
expected.To = ""
expected.Payload = "0x68656c6c6f20776f726c64"
expected.Priority = 100
expected.Ttl = 100
expected.Topics = []string{"0x68656c6c6f20776f726c64"}
args := new(WhisperMessageArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.From != args.From {
t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
}
if expected.To != args.To {
t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
}
if expected.Payload != args.Payload {
t.Errorf("Value shoud be %#v but is %#v", expected.Payload, args.Payload)
}
if expected.Ttl != args.Ttl {
t.Errorf("Ttl shoud be %#v but is %#v", expected.Ttl, args.Ttl)
}
if expected.Priority != args.Priority {
t.Errorf("Priority shoud be %#v but is %#v", expected.Priority, args.Priority)
}
// if expected.Topics != args.Topics {
// t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic)
// }
}
func TestFilterIdArgs(t *testing.T) {
input := `["0x7"]`
expected := new(FilterIdArgs)
expected.Id = 7
args := new(FilterIdArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.Id != args.Id {
t.Errorf("Id shoud be %#v but is %#v", expected.Id, args.Id)
}
}
func TestWhsiperFilterArgs(t *testing.T) {
input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": "0x34ag445g3455b34"}]`
expected := new(WhisperFilterArgs)
expected.From = ""
expected.To = "0x34ag445g3455b34"
expected.Topics = []string{"0x68656c6c6f20776f726c64"}
args := new(WhisperFilterArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.From != args.From {
t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
}
if expected.To != args.To {
t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
}
// if expected.Topics != args.Topics {
// t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
// }
}
func TestCompileArgs(t *testing.T) {
input := `["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"]`
expected := new(CompileArgs)
expected.Source = `contract test { function multiply(uint a) returns(uint d) { return a * 7; } }`
args := new(CompileArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.Source != args.Source {
t.Errorf("Source shoud be %#v but is %#v", expected.Source, args.Source)
}
}
func TestFilterStringArgs(t *testing.T) {
input := `["pending"]`
expected := new(FilterStringArgs)
expected.Word = "pending"
args := new(FilterStringArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.Word != args.Word {
t.Errorf("Word shoud be %#v but is %#v", expected.Word, args.Word)
}
}
func TestWhisperIdentityArgs(t *testing.T) {
input := `["0xc931d93e97ab07fe42d923478ba2465f283"]`
expected := new(WhisperIdentityArgs)
expected.Identity = "0xc931d93e97ab07fe42d923478ba2465f283"
args := new(WhisperIdentityArgs)
if err := json.Unmarshal([]byte(input), &args); err != nil {
t.Error(err)
}
if expected.Identity != args.Identity {
t.Errorf("Identity shoud be %#v but is %#v", expected.Identity, args.Identity)
}
}

View File

@ -17,12 +17,9 @@
package rpc package rpc
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/xeth"
) )
var ( var (
@ -33,10 +30,10 @@ var (
) )
type RpcRequest struct { type RpcRequest struct {
ID interface{} `json:"id"` ID interface{} `json:"id"`
JsonRpc string `json:"jsonrpc"` JsonRpc string `json:"jsonrpc"`
Method string `json:"method"` Method string `json:"method"`
Params []json.RawMessage `json:"params"` Params json.RawMessage `json:"params"`
} }
type RpcSuccessResponse struct { type RpcSuccessResponse struct {
@ -61,359 +58,30 @@ func NewErrorWithMessage(err error, msg string) error {
return fmt.Errorf("%s: %s", err.Error(), msg) return fmt.Errorf("%s: %s", err.Error(), msg)
} }
func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { // func (req *RpcRequest) ToRegisterArgs() (string, error) {
if len(req.Params) < 1 { // if len(req.Params) < 1 {
return nil, errArguments // return "", errArguments
} // }
args := new(Sha3Args) // var args string
r := bytes.NewReader(req.Params[0]) // err := json.Unmarshal(req.Params, &args)
if err := json.NewDecoder(r).Decode(args); err != nil { // if err != nil {
return nil, errDecodeArgs // return "", err
} // }
return args, nil // return args, nil
} // }
func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { // func (req *RpcRequest) ToWatchTxArgs() (string, error) {
if len(req.Params) < 1 { // if len(req.Params) < 1 {
return nil, errArguments // return "", errArguments
} // }
args := new(GetBlockArgs) // var args string
r := bytes.NewReader(req.Params[0]) // err := json.Unmarshal(req.Params, &args)
err := json.NewDecoder(r).Decode(args) // if err != nil {
if err != nil { // return "", err
return nil, errDecodeArgs // }
}
// return args, nil
return args, nil // }
}
func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(NewTxArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
return args, nil
}
func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(PushTxArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetStateArgs)
// TODO need to pass both arguments
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetStorageArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetTxCountArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetBalanceArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetCodeAtArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToBoolArgs() (bool, error) {
if len(req.Params) < 1 {
return false, errArguments
}
var args bool
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return false, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToIntArgs() (int, error) {
if len(req.Params) < 1 {
return 0, errArguments
}
var args int
if err := json.Unmarshal(req.Params[0], &args); err != nil {
return 0, errArguments
}
return args, nil
}
func (req *RpcRequest) ToCompileArgs() (string, error) {
if len(req.Params) < 1 {
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(FilterOptions)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToFilterStringArgs() (string, error) {
if len(req.Params) < 1 {
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToUninstallFilterArgs() (int, error) {
if len(req.Params) < 1 {
return 0, errArguments
}
var args int
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return 0, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToFilterChangedArgs() (int, error) {
if len(req.Params) < 1 {
return 0, errArguments
}
var id int
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(&id)
if err != nil {
return 0, errDecodeArgs
}
return id, nil
}
func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) {
if len(req.Params) < 3 {
return nil, errArguments
}
var args DbArgs
err := json.Unmarshal(req.Params[0], &args.Database)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[1], &args.Key)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[2], &args.Value)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
return &args, nil
}
func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) {
if len(req.Params) < 2 {
return nil, errArguments
}
var args DbArgs
err := json.Unmarshal(req.Params[0], &args.Database)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
err = json.Unmarshal(req.Params[1], &args.Key)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
return &args, nil
}
func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
var args xeth.Options
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
}
return &args, nil
}
func (req *RpcRequest) ToIdArgs() (int, error) {
if len(req.Params) < 1 {
return 0, errArguments
}
var id int
err := json.Unmarshal(req.Params[0], &id)
if err != nil {
return 0, errDecodeArgs
}
return id, nil
}
func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
var args WhisperMessageArgs
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return nil, err
}
return &args, nil
}
func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) {
if len(req.Params) < 1 {
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", err
}
return args, nil
}
func (req *RpcRequest) ToRegisterArgs() (string, error) {
if len(req.Params) < 1 {
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", err
}
return args, nil
}
func (req *RpcRequest) ToWatchTxArgs() (string, error) {
if len(req.Params) < 1 {
return "", errArguments
}
var args string
err := json.Unmarshal(req.Params[0], &args)
if err != nil {
return "", err
}
return args, nil
}

212
rpc/responses.go Normal file
View File

@ -0,0 +1,212 @@
package rpc
import (
"encoding/json"
// "fmt"
"math/big"
"github.com/ethereum/go-ethereum/core/types"
)
type BlockRes struct {
fullTx bool
BlockNumber int64 `json:"number"`
BlockHash []byte `json:"hash"`
ParentHash []byte `json:"parentHash"`
Nonce []byte `json:"nonce"`
Sha3Uncles []byte `json:"sha3Uncles"`
LogsBloom []byte `json:"logsBloom"`
TransactionRoot []byte `json:"transactionRoot"`
StateRoot []byte `json:"stateRoot"`
Miner []byte `json:"miner"`
Difficulty int64 `json:"difficulty"`
TotalDifficulty int64 `json:"totalDifficulty"`
Size int64 `json:"size"`
ExtraData []byte `json:"extraData"`
GasLimit int64 `json:"gasLimit"`
MinGasPrice int64 `json:"minGasPrice"`
GasUsed int64 `json:"gasUsed"`
UnixTimestamp int64 `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"`
Uncles [][]byte `json:"uncles"`
}
func (b *BlockRes) MarshalJSON() ([]byte, error) {
var ext struct {
BlockNumber string `json:"number"`
BlockHash string `json:"hash"`
ParentHash string `json:"parentHash"`
Nonce string `json:"nonce"`
Sha3Uncles string `json:"sha3Uncles"`
LogsBloom string `json:"logsBloom"`
TransactionRoot string `json:"transactionRoot"`
StateRoot string `json:"stateRoot"`
Miner string `json:"miner"`
Difficulty string `json:"difficulty"`
TotalDifficulty string `json:"totalDifficulty"`
Size string `json:"size"`
ExtraData string `json:"extraData"`
GasLimit string `json:"gasLimit"`
MinGasPrice string `json:"minGasPrice"`
GasUsed string `json:"gasUsed"`
UnixTimestamp string `json:"timestamp"`
Transactions []interface{} `json:"transactions"`
Uncles []string `json:"uncles"`
}
// convert strict types to hexified strings
ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes())
ext.BlockHash = toHex(b.BlockHash)
ext.ParentHash = toHex(b.ParentHash)
ext.Nonce = toHex(b.Nonce)
ext.Sha3Uncles = toHex(b.Sha3Uncles)
ext.LogsBloom = toHex(b.LogsBloom)
ext.TransactionRoot = toHex(b.TransactionRoot)
ext.StateRoot = toHex(b.StateRoot)
ext.Miner = toHex(b.Miner)
ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes())
ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes())
ext.Size = toHex(big.NewInt(b.Size).Bytes())
// ext.ExtraData = toHex(b.ExtraData)
ext.GasLimit = toHex(big.NewInt(b.GasLimit).Bytes())
// ext.MinGasPrice = toHex(big.NewInt(b.MinGasPrice).Bytes())
ext.GasUsed = toHex(big.NewInt(b.GasUsed).Bytes())
ext.UnixTimestamp = toHex(big.NewInt(b.UnixTimestamp).Bytes())
ext.Transactions = make([]interface{}, len(b.Transactions))
if b.fullTx {
for i, tx := range b.Transactions {
ext.Transactions[i] = tx
}
} else {
for i, tx := range b.Transactions {
ext.Transactions[i] = toHex(tx.Hash)
}
}
ext.Uncles = make([]string, len(b.Uncles))
for i, v := range b.Uncles {
ext.Uncles[i] = toHex(v)
}
return json.Marshal(ext)
}
func NewBlockRes(block *types.Block) *BlockRes {
if block == nil {
return &BlockRes{}
}
res := new(BlockRes)
res.BlockNumber = block.Number().Int64()
res.BlockHash = block.Hash()
res.ParentHash = block.ParentHash()
res.Nonce = block.Header().Nonce
res.Sha3Uncles = block.Header().UncleHash
res.LogsBloom = block.Bloom()
res.TransactionRoot = block.Header().TxHash
res.StateRoot = block.Root()
res.Miner = block.Header().Coinbase
res.Difficulty = block.Difficulty().Int64()
if block.Td != nil {
res.TotalDifficulty = block.Td.Int64()
}
res.Size = int64(block.Size())
// res.ExtraData =
res.GasLimit = block.GasLimit().Int64()
// res.MinGasPrice =
res.GasUsed = block.GasUsed().Int64()
res.UnixTimestamp = block.Time()
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
for i, tx := range block.Transactions() {
v := NewTransactionRes(tx)
v.BlockHash = block.Hash()
v.BlockNumber = block.Number().Int64()
v.TxIndex = int64(i)
res.Transactions[i] = v
}
res.Uncles = make([][]byte, len(block.Uncles()))
for i, uncle := range block.Uncles() {
res.Uncles[i] = uncle.Hash()
}
return res
}
type TransactionRes struct {
Hash []byte `json:"hash"`
Nonce int64 `json:"nonce"`
BlockHash []byte `json:"blockHash,omitempty"`
BlockNumber int64 `json:"blockNumber,omitempty"`
TxIndex int64 `json:"transactionIndex,omitempty"`
From []byte `json:"from"`
To []byte `json:"to"`
Value int64 `json:"value"`
Gas int64 `json:"gas"`
GasPrice int64 `json:"gasPrice"`
Input []byte `json:"input"`
}
func (t *TransactionRes) MarshalJSON() ([]byte, error) {
var ext struct {
Hash string `json:"hash"`
Nonce string `json:"nonce"`
BlockHash string `json:"blockHash,omitempty"`
BlockNumber string `json:"blockNumber,omitempty"`
TxIndex string `json:"transactionIndex,omitempty"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Input string `json:"input"`
}
ext.Hash = toHex(t.Hash)
ext.Nonce = toHex(big.NewInt(t.Nonce).Bytes())
ext.BlockHash = toHex(t.BlockHash)
ext.BlockNumber = toHex(big.NewInt(t.BlockNumber).Bytes())
ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes())
ext.From = toHex(t.From)
ext.To = toHex(t.To)
ext.Value = toHex(big.NewInt(t.Value).Bytes())
ext.Gas = toHex(big.NewInt(t.Gas).Bytes())
ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes())
ext.Input = toHex(t.Input)
return json.Marshal(ext)
}
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
var v = new(TransactionRes)
v.Hash = tx.Hash()
v.Nonce = int64(tx.Nonce())
v.From = tx.From()
v.To = tx.To()
v.Value = tx.Value().Int64()
v.Gas = tx.Gas().Int64()
v.GasPrice = tx.GasPrice().Int64()
v.Input = tx.Data()
return v
}
type FilterLogRes struct {
Hash string `json:"hash"`
Address string `json:"address"`
Data string `json:"data"`
BlockNumber string `json:"blockNumber"`
TransactionHash string `json:"transactionHash"`
BlockHash string `json:"blockHash"`
TransactionIndex string `json:"transactionIndex"`
LogIndex string `json:"logIndex"`
}
type FilterWhisperRes struct {
Hash string `json:"hash"`
From string `json:"from"`
To string `json:"to"`
Expiry string `json:"expiry"`
Sent string `json:"sent"`
Ttl string `json:"ttl"`
Topics string `json:"topics"`
Payload string `json:"payload"`
WorkProved string `json:"workProved"`
}

View File

@ -18,8 +18,11 @@ package rpc
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"math/big"
"net/http" "net/http"
"reflect"
"time" "time"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
@ -32,9 +35,63 @@ var rpclogger = logger.NewLogger("RPC")
type JsonWrapper struct{} type JsonWrapper struct{}
// Unmarshal state is a helper method which has the ability to decode messsages
// that use the `defaultBlock` (https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter)
// For example a `call`: [{to: "0x....", data:"0x..."}, "latest"]. The first argument is the transaction
// message and the second one refers to the block height (or state) to which to apply this `call`.
func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error) {
var data []json.RawMessage
if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
return errDecodeArgs
}
// Number index determines the index in the array for a possible block number
numberIndex := 0
value := reflect.ValueOf(iface)
rvalue := reflect.Indirect(value)
switch rvalue.Kind() {
case reflect.Slice:
// This is a bit of a cheat, but `data` is expected to be larger than 2 if iface is a slice
if number != nil {
numberIndex = len(data) - 1
} else {
numberIndex = len(data)
}
slice := reflect.MakeSlice(rvalue.Type(), numberIndex, numberIndex)
for i, raw := range data[0:numberIndex] {
v := slice.Index(i).Interface()
if err = json.Unmarshal(raw, &v); err != nil {
fmt.Println(err, v)
return err
}
slice.Index(i).Set(reflect.ValueOf(v))
}
reflect.Indirect(rvalue).Set(slice) //value.Set(slice)
case reflect.Struct:
fallthrough
default:
if err = json.Unmarshal(data[0], iface); err != nil {
return errDecodeArgs
}
numberIndex = 1
}
// <0 index means out of bound for block number
if numberIndex >= 0 && len(data) > numberIndex {
if err = blockNumber(data[numberIndex], number); err != nil {
return errDecodeArgs
}
}
return nil
}
func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) {
var payload []byte var payload []byte
payload, err = json.Marshal(v) payload, err = json.MarshalIndent(v, "", "\t")
if err != nil { if err != nil {
rpclogger.Fatalln("Error marshalling JSON", err) rpclogger.Fatalln("Error marshalling JSON", err)
return 0, err return 0, err
@ -63,18 +120,31 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error)
} }
func toHex(b []byte) string { func toHex(b []byte) string {
return "0x" + ethutil.Bytes2Hex(b) hex := ethutil.Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 {
hex = "0"
}
return "0x" + hex
} }
func fromHex(s string) []byte { func fromHex(s string) []byte {
if len(s) > 1 { if len(s) > 1 {
if s[0:2] == "0x" { if s[0:2] == "0x" {
s = s[2:] s = s[2:]
} }
if len(s)%2 == 1 {
s = "0" + s
}
return ethutil.Hex2Bytes(s) return ethutil.Hex2Bytes(s)
} }
return nil return nil
} }
func i2hex(n int) string {
return toHex(big.NewInt(int64(n)).Bytes())
}
type RpcServer interface { type RpcServer interface {
Start() Start()
Stop() Stop()

25
rpc/util_test.go Normal file
View File

@ -0,0 +1,25 @@
package rpc
import (
"bytes"
"testing"
)
//fromHex
func TestFromHex(t *testing.T) {
input := "0x01"
expected := []byte{1}
result := fromHex(input)
if bytes.Compare(expected, result) != 0 {
t.Errorf("Expected % x got % x", expected, result)
}
}
func TestFromHexOddLength(t *testing.T) {
input := "0x1"
expected := []byte{1}
result := fromHex(input)
if bytes.Compare(expected, result) != 0 {
t.Errorf("Expected % x got % x", expected, result)
}
}

View File

@ -37,7 +37,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
context := NewContext(caller, me, code, gas, price) context := NewContext(caller, me, code, gas, price)
vmlogger.Debugf("(%d) (%x) %x (code=%d) gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData) self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl()
if self.Recoverable { if self.Recoverable {
// Recover from any require exception // Recover from any require exception
@ -696,7 +696,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
if err != nil { if err != nil {
stack.push(ethutil.BigFalse) stack.push(ethutil.BigFalse)
vmlogger.Debugln(err) self.Printf("%v").Endl()
} else { } else {
stack.push(ethutil.BigTrue) stack.push(ethutil.BigTrue)
@ -726,7 +726,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
return context.Return(nil), nil return context.Return(nil), nil
default: default:
vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
panic(fmt.Errorf("Invalid opcode %x", op)) panic(fmt.Errorf("Invalid opcode %x", op))
} }
@ -894,7 +894,7 @@ func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
func (self *Vm) Endl() VirtualMachine { func (self *Vm) Endl() VirtualMachine {
if self.debug { if self.debug {
if self.logTy == LogTyPretty { if self.logTy == LogTyPretty {
vmlogger.Debugln(self.logStr) vmlogger.Infoln(self.logStr)
self.logStr = "" self.logStr = ""
} }
} }

View File

@ -98,7 +98,7 @@ func New(eth Backend, frontend Frontend) *XEth {
} }
func (self *XEth) Backend() Backend { return self.eth } func (self *XEth) Backend() Backend { return self.eth }
func (self *XEth) UseState(statedb *state.StateDB) *XEth { func (self *XEth) WithState(statedb *state.StateDB) *XEth {
xeth := &XEth{ xeth := &XEth{
eth: self.eth, eth: self.eth,
blockProcessor: self.blockProcessor, blockProcessor: self.blockProcessor,
@ -122,7 +122,14 @@ func (self *XEth) BlockByHash(strHash string) *Block {
return NewBlock(block) return NewBlock(block)
} }
func (self *XEth) BlockByNumber(num int32) *Block { func (self *XEth) EthBlockByHash(strHash string) *types.Block {
hash := fromHex(strHash)
block := self.chainManager.GetBlock(hash)
return block
}
func (self *XEth) BlockByNumber(num int64) *Block {
if num == -1 { if num == -1 {
return NewBlock(self.chainManager.CurrentBlock()) return NewBlock(self.chainManager.CurrentBlock())
} }
@ -130,13 +137,21 @@ func (self *XEth) BlockByNumber(num int32) *Block {
return NewBlock(self.chainManager.GetBlockByNumber(uint64(num))) return NewBlock(self.chainManager.GetBlockByNumber(uint64(num)))
} }
func (self *XEth) EthBlockByNumber(num int64) *types.Block {
if num == -1 {
return self.chainManager.CurrentBlock()
}
return self.chainManager.GetBlockByNumber(uint64(num))
}
func (self *XEth) Block(v interface{}) *Block { func (self *XEth) Block(v interface{}) *Block {
if n, ok := v.(int32); ok { if n, ok := v.(int32); ok {
return self.BlockByNumber(n) return self.BlockByNumber(int64(n))
} else if str, ok := v.(string); ok { } else if str, ok := v.(string); ok {
return self.BlockByHash(str) return self.BlockByHash(str)
} else if f, ok := v.(float64); ok { // Don't ask ... } else if f, ok := v.(float64); ok { // Don't ask ...
return self.BlockByNumber(int32(f)) return self.BlockByNumber(int64(f))
} }
return nil return nil
@ -278,14 +293,12 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
return toHex(tx.Hash()), nil return toHex(tx.Hash()), nil
} }
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) { var (
if len(gasStr) == 0 { defaultGasPrice = big.NewInt(10000000000000)
gasStr = "100000" defaultGas = big.NewInt(90000)
} )
if len(gasPriceStr) == 0 {
gasPriceStr = "1"
}
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
statedb := self.State().State() //self.chainManager.TransState() statedb := self.State().State() //self.chainManager.TransState()
msg := callmsg{ msg := callmsg{
from: statedb.GetOrNewStateObject(fromHex(fromStr)), from: statedb.GetOrNewStateObject(fromHex(fromStr)),
@ -295,6 +308,14 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
value: ethutil.Big(valueStr), value: ethutil.Big(valueStr),
data: fromHex(dataStr), data: fromHex(dataStr),
} }
if msg.gas.Cmp(big.NewInt(0)) == 0 {
msg.gas = defaultGas
}
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
msg.gasPrice = defaultGasPrice
}
block := self.chainManager.CurrentBlock() block := self.chainManager.CurrentBlock()
vmenv := core.NewEnv(statedb, self.chainManager, msg, block) vmenv := core.NewEnv(statedb, self.chainManager, msg, block)
@ -327,7 +348,7 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data) tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
} }
state := self.chainManager.TransState() state := self.chainManager.TxState()
nonce := state.GetNonce(from) nonce := state.GetNonce(from)
tx.SetNonce(nonce) tx.SetNonce(nonce)