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"
"runtime"
"strconv"
"strings"
"time"
"github.com/codegangsta/cli"
@ -112,6 +113,7 @@ runtime will execute the file and exit.
},
}
app.Flags = []cli.Flag{
utils.UnlockedAccountFlag,
utils.BootnodesFlag,
utils.DataDirFlag,
utils.ListenPortFlag,
@ -191,6 +193,21 @@ Please run 'ethereum account new' to create a new account.`)
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
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.
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
utils.StartRPC(eth, ctx)

View File

@ -35,7 +35,7 @@
var web3 = require('web3');
var eth = web3.eth;
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var desc = [{
"name": "balance(address)",
"type": "function",
@ -72,12 +72,13 @@
// deploy if not exist
if (address == null) {
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.transact({data: code});
address = web3.eth.transact({from: eth.coinbase, data: code});
localStorage.setItem("address", 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() {
refresh();
});
@ -88,7 +89,7 @@
var table = document.querySelector("#table_body");
table.innerHTML = ""; // clear
var storage = eth.storageAt(address);
var storage = eth.getStorage(address);
table.innerHTML = "";
for( var item in storage ) {
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",
}
*/
UnlockedAccountFlag = cli.StringFlag{
Name: "unlock",
Usage: "Unlock a given account untill this programs exits (address:password)",
}
VMDebugFlag = cli.BoolFlag{
Name: "vmdebug",
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 {
dataDir := ctx.GlobalString(DataDirFlag.Name)
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) {

View File

@ -80,7 +80,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
cb := statedb.GetStateObject(coinbase.Address())
st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb)
_, 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
}
@ -120,17 +120,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
for _, tx := range txs {
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 {
switch {
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
}
statelogger.Infoln("TX err:", err)
}
receipts = append(receipts, receipt)
handled = append(handled, tx)

View File

@ -440,12 +440,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td)
self.insert(block)
/* XXX crashes
jsonlogger.LogJson(&logger.EthChainNewHead{
BlockHash: ethutil.Bytes2Hex(block.Hash()),
BlockNumber: block.Number(),
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
})
*/
self.setTransState(state.New(block.Root(), self.stateDb))
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 {
println("2")
return nil, InvalidTxError(err)
}
@ -198,48 +199,18 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
dataGas.Mul(dataGas, vm.GasCreateByte)
if err := self.UseGas(dataGas); err == nil {
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 {
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) {
return nil, InvalidTxError(err)
}
/*
if err != nil {
self.UseGas(self.gas)
}
*/
return
}

View File

@ -58,7 +58,7 @@ type JSEthereum struct {
func (self *JSEthereum) Block(v interface{}) otto.Value {
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 {
return self.toVal(&JSBlock{self.XEth.BlockByHash(hash), self})
}

View File

@ -209,6 +209,8 @@ gasLimit:
err := self.commitTransaction(tx)
switch {
case core.IsNonceErr(err):
fallthrough
case core.IsInvalidTxErr(err):
// Remove invalid transactions
remove = append(remove, tx)
case state.IsGasLimitErr(err):
@ -222,7 +224,7 @@ gasLimit:
}
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.push()
@ -258,9 +260,11 @@ func (self *worker) commitUncle(uncle *types.Header) 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())
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
}

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
import (
"encoding/json"
"fmt"
"math/big"
"path"
"strings"
@ -27,8 +21,8 @@ import (
)
var (
defaultGasPrice = big.NewInt(10000000000000)
defaultGas = big.NewInt(10000)
defaultGasPrice = big.NewInt(150000000000)
defaultGas = big.NewInt(500000)
filterTickerTime = 15 * time.Second
)
@ -50,21 +44,18 @@ type EthereumApi struct {
register map[string][]*NewTxArgs
db ethutil.Database
defaultBlockAge int64
}
func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
api := &EthereumApi{
eth: eth,
mux: eth.Backend().EventMux(),
quit: make(chan struct{}),
filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter),
db: db,
defaultBlockAge: -1,
eth: eth,
mux: eth.Backend().EventMux(),
quit: make(chan struct{}),
filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
logs: make(map[int]*logFilter),
messages: make(map[int]*whisperFilter),
db: db,
}
go api.filterManager.Start()
go api.start()
@ -72,36 +63,33 @@ func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
return api
}
func (self *EthereumApi) setStateByBlockNumber(num int64) {
func (self *EthereumApi) xethWithStateNum(num int64) *xeth.XEth {
chain := self.xeth().Backend().ChainManager()
var block *types.Block
if self.defaultBlockAge < 0 {
if num < 0 {
num = chain.CurrentBlock().Number().Int64() + num + 1
}
block = chain.GetBlockByNumber(uint64(num))
var st *state.StateDB
if block != nil {
self.useState(state.New(block.Root(), self.xeth().Backend().StateDb()))
st = state.New(block.Root(), self.xeth().Backend().StateDb())
} 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() {
timer := time.NewTicker(filterTickerTime)
events := self.mux.Subscribe(core.ChainEvent{})
done:
for {
select {
case ev := <-events.Chan():
switch ev.(type) {
case core.ChainEvent:
if self.defaultBlockAge < 0 {
self.setStateByBlockNumber(self.defaultBlockAge)
}
}
case <-timer.C:
self.logMut.Lock()
self.messagesMut.Lock()
@ -130,35 +118,35 @@ func (self *EthereumApi) stop() {
close(self.quit)
}
func (self *EthereumApi) Register(args string, reply *interface{}) error {
self.regmut.Lock()
defer self.regmut.Unlock()
// func (self *EthereumApi) Register(args string, reply *interface{}) error {
// self.regmut.Lock()
// defer self.regmut.Unlock()
if _, ok := self.register[args]; ok {
self.register[args] = nil // register with empty
}
return nil
}
// if _, ok := self.register[args]; ok {
// self.register[args] = nil // register with empty
// }
// return nil
// }
func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
self.regmut.Lock()
defer self.regmut.Unlock()
// func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
// self.regmut.Lock()
// 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 {
self.regmut.Lock()
defer self.regmut.Unlock()
// func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
// self.regmut.Lock()
// defer self.regmut.Unlock()
txs := self.register[args]
self.register[args] = nil
// txs := self.register[args]
// self.register[args] = nil
*reply = txs
return nil
}
// *reply = txs
// return nil
// }
func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
var id int
@ -173,7 +161,7 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id
*reply = i2hex(id)
return nil
}
@ -203,7 +191,7 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id
*reply = i2hex(id)
return nil
}
@ -240,35 +228,49 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error
return nil
}
func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
// This seems a bit precarious Maybe worth splitting to discrete functions
if len(args.Hash) > 0 {
*reply = p.xeth().BlockByHash(args.Hash)
} else {
*reply = p.xeth().BlockByNumber(args.BlockNumber)
}
return nil
}
func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) (err error) {
// TODO if no_private_key then
//if _, exists := p.register[args.From]; exists {
// p.register[args.From] = append(p.register[args.From], args)
//} else {
/*
account := accounts.Get(fromHex(args.From))
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
// ethutil.Value conversions later on
if ethutil.Big(args.Gas).Cmp(big.NewInt(0)) == 0 {
args.Gas = defaultGas.String()
if args.Gas.Cmp(big.NewInt(0)) == 0 {
args.Gas = defaultGas
}
if ethutil.Big(args.GasPrice).Cmp(big.NewInt(0)) == 0 {
args.GasPrice = defaultGasPrice.String()
if args.GasPrice.Cmp(big.NewInt(0)) == 0 {
args.GasPrice = defaultGasPrice
}
result, _ := p.xeth().Transact(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data)
*reply = result
*reply, err = p.xeth().Transact(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
if err != nil {
fmt.Println("err:", err)
return err
}
return nil
}
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 {
return err
}
@ -277,23 +279,28 @@ func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
return nil
}
func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
err := args.requirementsPushTx()
if err != nil {
func (p *EthereumApi) GetBalance(args *GetBalanceArgs, reply *interface{}) error {
if err := args.requirements(); err != nil {
return err
}
result, _ := p.xeth().PushTx(args.Tx)
*reply = result
state := p.getStateWithNum(args.BlockNumber).SafeGet(args.Address)
*reply = toHex(state.Balance().Bytes())
return nil
}
func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
func (p *EthereumApi) GetStorage(args *GetStorageArgs, reply *interface{}) error {
if err := args.requirements(); err != nil {
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)
var hx string
@ -309,115 +316,31 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
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 {
err := args.requirements()
if err != nil {
return err
}
*reply = p.xeth().TxCountAt(args.Address)
*reply = p.xethWithStateNum(args.BlockNumber).TxCountAt(args.Address)
return nil
}
func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
func (p *EthereumApi) GetData(args *GetDataArgs, reply *interface{}) error {
if err := args.requirements(); err != nil {
return err
}
state := p.xeth().State().SafeGet(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)
*reply = p.xethWithStateNum(args.BlockNumber).CodeAt(args.Address)
return nil
}
func (p *EthereumApi) GetCompilers(reply *interface{}) error {
c := []string{"serpent"}
c := []string{""}
*reply = c
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 {
err := args.requirements()
if err != nil {
if err := args.requirements(); err != nil {
return err
}
@ -427,8 +350,7 @@ func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
}
func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
if err := args.requirements(); err != nil {
return err
}
@ -442,14 +364,18 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
return nil
}
func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) error {
func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
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()
defer p.messagesMut.Unlock()
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()}
*reply = id
return nil
@ -467,7 +393,7 @@ func (self *EthereumApi) MessagesChanged(id int, 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 {
return err
}
@ -486,199 +412,358 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
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 {
// 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 {
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":
return p.GetCoinbase(reply)
case "eth_listening":
return p.GetIsListening(reply)
*reply = p.xeth().Coinbase()
case "eth_mining":
return p.GetIsMining(reply)
case "eth_setMining":
args, err := req.ToBoolArgs()
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)
*reply = p.xeth().IsMining()
case "eth_gasPrice":
*reply = toHex(defaultGasPrice.Bytes())
case "eth_accounts":
return p.Accounts(reply)
case "eth_countAt":
args, err := req.ToGetTxCountArgs()
if err != nil {
*reply = p.xeth().Accounts()
case "eth_blockNumber":
*reply = toHex(p.xeth().Backend().ChainManager().CurrentBlock().Number().Bytes())
case "eth_getBalance":
args := new(GetBalanceArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetTxCountAt(args, reply)
case "eth_codeAt":
args, err := req.ToGetCodeAtArgs()
if err != nil {
return p.GetBalance(args, reply)
case "eth_getStorage", "eth_storageAt":
args := new(GetStorageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetCodeAt(args, reply)
case "eth_balanceAt":
args, err := req.ToGetBalanceArgs()
if 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 p.GetStorage(args, reply)
case "eth_getStorageAt":
args := new(GetStorageAtArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetStorageAt(args, reply)
case "eth_blockByNumber", "eth_blockByHash":
args, err := req.ToGetBlockArgs()
case "eth_getTransactionCount":
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 {
return err
}
return p.GetBlock(args, reply)
case "eth_transact":
args, err := req.ToNewTxArgs()
*reply = toHex(big.NewInt(v).Bytes())
case "eth_getBlockTransactionCountByNumber":
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := p.GetBlockTransactionCountByNumber(args.BlockNumber)
if err != nil {
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)
case "eth_call":
args, err := req.ToNewTxArgs()
if err != nil {
args := new(NewTxArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.Call(args, reply)
case "eth_newFilter":
args, err := req.ToFilterArgs()
case "eth_flush":
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 {
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)
case "eth_newFilterString":
args, err := req.ToFilterStringArgs()
if err != nil {
case "eth_newBlockFilter":
args := new(FilterStringArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.NewFilterString(args, reply)
return p.NewFilterString(args.Word, reply)
case "eth_uninstallFilter":
args, err := req.ToUninstallFilterArgs()
if err != nil {
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.UninstallFilter(args, reply)
case "eth_changed":
args, err := req.ToIdArgs()
if err != nil {
return p.UninstallFilter(args.Id, reply)
case "eth_getFilterChanges":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.FilterChanged(args, reply)
case "eth_filterLogs":
args, err := req.ToIdArgs()
if err != nil {
return p.FilterChanged(args.Id, reply)
case "eth_getFilterLogs":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.Logs(args, reply)
case "eth_logs":
args, err := req.ToFilterArgs()
if err != nil {
return p.Logs(args.Id, reply)
case "eth_getLogs":
args := new(FilterOptions)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.AllLogs(args, reply)
case "eth_gasPrice":
*reply = toHex(defaultGasPrice.Bytes())
return nil
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 "eth_getWork":
case "eth_submitWork":
return errNotImplemented
case "db_put":
args, err := req.ToDbPutArgs()
if err != nil {
args := new(DbArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.DbPut(args, reply)
case "db_get":
args, err := req.ToDbGetArgs()
if err != nil {
args := new(DbArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
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":
args, err := req.ToWhisperPostArgs()
if err != nil {
args := new(WhisperMessageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.WhisperPost(args, reply)
case "shh_haveIdentity":
args, err := req.ToWhisperHasIdentityArgs()
if err != nil {
case "shh_newIdentity":
return p.NewWhisperIdentity(reply)
case "shh_hasIdentity":
args := new(WhisperIdentityArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
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":
args, err := req.ToIdArgs()
if err != nil {
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
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:
return NewErrorWithMessage(errNotImplemented, req.Method)
}
@ -694,9 +779,38 @@ func (self *EthereumApi) xeth() *xeth.XEth {
return self.eth
}
func (self *EthereumApi) useState(statedb *state.StateDB) {
self.xethMu.Lock()
defer self.xethMu.Unlock()
func toFilterOptions(options *FilterOptions) core.FilterOptions {
var opts core.FilterOptions
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
import (
"encoding/json"
"sync"
"testing"
"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) {
t.Skip()
api := &EthereumApi{

View File

@ -1,247 +1,331 @@
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 {
BlockNumber int32
Hash string
func blockNumber(raw json.RawMessage, number *int64) (err error) {
var str 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) {
argint, argstr := int32(0), ""
if err = json.Unmarshal(b, &argint); err == nil {
obj.BlockNumber = argint
return
type GetBlockByHashArgs struct {
BlockHash string
Transactions bool
}
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
return
if len(obj) < 1 {
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 {
From string `json:"from"`
Pass string `json:"pass"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Data string `json:"data"`
From string
To string
Value *big.Int
Gas *big.Int
GasPrice *big.Int
Data string
BlockNumber int64
}
func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
// Data can be either specified as "data" or "code" :-/
var ext struct {
From string
To string
Value string
Gas string
GasPrice string
Data string
Code string
func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
var obj struct{ From, To, Value, Gas, GasPrice, Data string }
if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return err
}
if err = json.Unmarshal(b, &ext); err == nil {
if len(ext.Data) == 0 {
ext.Data = ext.Code
}
obj.From = ext.From
obj.To = ext.To
obj.Value = ext.Value
obj.Gas = ext.Gas
obj.GasPrice = ext.GasPrice
obj.Data = ext.Data
args.From = obj.From
args.To = obj.To
args.Value = ethutil.Big(obj.Value)
args.Gas = ethutil.Big(obj.Gas)
args.GasPrice = ethutil.Big(obj.GasPrice)
args.Data = obj.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
}
type GetStorageArgs struct {
Address string
Address string
BlockNumber int64
}
func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Address); err != nil {
func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
return
return nil
}
func (a *GetStorageArgs) requirements() error {
if len(a.Address) == 0 {
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
func (args *GetStorageArgs) requirements() error {
if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
type GetStateArgs struct {
Address string
Key string
type GetStorageAtArgs struct {
Address string
Key string
BlockNumber int64
}
func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0
return
func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
var obj []string
if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return errDecodeArgs
}
return errDecodeArgs
if len(obj) < 2 {
return errDecodeArgs
}
args.Address = obj[0]
args.Key = obj[1]
return nil
}
func (a *GetStateArgs) requirements() error {
if a.Address == "" {
return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
func (args *GetStorageAtArgs) requirements() error {
if len(args.Address) == 0 {
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
}
type GetTxCountArgs struct {
Address string `json:"address"`
Address string
BlockNumber int64
}
func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0
return
func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
return errDecodeArgs
return nil
}
func (a *GetTxCountArgs) requirements() error {
if a.Address == "" {
return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument")
func (args *GetTxCountArgs) requirements() error {
if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
type GetBalanceArgs struct {
Address string
Address string
BlockNumber int64
}
func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0
return
func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
return errDecodeArgs
return nil
}
func (a *GetBalanceArgs) requirements() error {
if a.Address == "" {
return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument")
func (args *GetBalanceArgs) requirements() error {
if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
type GetCodeAtArgs struct {
Address string
type GetDataArgs struct {
Address string
BlockNumber int64
}
func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, &arg0); err == nil {
obj.Address = arg0
return
func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
return errDecodeArgs
return nil
}
func (a *GetCodeAtArgs) requirements() error {
if a.Address == "" {
return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument")
func (args *GetDataArgs) requirements() error {
if len(args.Address) == 0 {
return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
type BlockNumIndexArgs struct {
BlockNumber int64
Index int64
}
type HashIndexArgs struct {
BlockHash string
Index int64
}
type Sha3Args struct {
Data string
}
func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) {
if err = json.Unmarshal(b, &obj.Data); err != nil {
return errDecodeArgs
func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
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 {
Earliest int64
Latest int64
Address interface{}
Topic []interface{}
Topics []interface{}
Skip int
Max int
}
func toFilterOptions(options *FilterOptions) core.FilterOptions {
var opts core.FilterOptions
// 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
func (args *FilterOptions) 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 []interface{} `json:"topics"`
}
opts.Earliest = options.Earliest
opts.Latest = options.Latest
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)
}
if err = json.Unmarshal(b, &obj); err != nil {
return errDecodeArgs
}
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 {
n int
}
// type FilterChangedArgs struct {
// n int
// }
type DbArgs struct {
Database string
@ -249,12 +333,32 @@ type DbArgs struct {
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 {
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 {
return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument")
return NewErrorWithMessage(errArguments, "Key cannot be blank")
}
return nil
}
@ -263,7 +367,140 @@ type WhisperMessageArgs struct {
Payload string
To string
From string
Topic []string
Topics []string
Priority 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
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/xeth"
)
var (
@ -33,10 +30,10 @@ var (
)
type RpcRequest struct {
ID interface{} `json:"id"`
JsonRpc string `json:"jsonrpc"`
Method string `json:"method"`
Params []json.RawMessage `json:"params"`
ID interface{} `json:"id"`
JsonRpc string `json:"jsonrpc"`
Method string `json:"method"`
Params json.RawMessage `json:"params"`
}
type RpcSuccessResponse struct {
@ -61,359 +58,30 @@ func NewErrorWithMessage(err error, msg string) error {
return fmt.Errorf("%s: %s", err.Error(), msg)
}
func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(Sha3Args)
r := bytes.NewReader(req.Params[0])
if err := json.NewDecoder(r).Decode(args); err != nil {
return nil, errDecodeArgs
}
return args, nil
}
func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) {
if len(req.Params) < 1 {
return nil, errArguments
}
args := new(GetBlockArgs)
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
if err != nil {
return nil, errDecodeArgs
}
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
}
// func (req *RpcRequest) ToRegisterArgs() (string, error) {
// if len(req.Params) < 1 {
// return "", errArguments
// }
// var args string
// err := json.Unmarshal(req.Params, &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, &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 (
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"reflect"
"time"
"github.com/ethereum/go-ethereum/ethutil"
@ -32,9 +35,63 @@ var rpclogger = logger.NewLogger("RPC")
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) {
var payload []byte
payload, err = json.Marshal(v)
payload, err = json.MarshalIndent(v, "", "\t")
if err != nil {
rpclogger.Fatalln("Error marshalling JSON", err)
return 0, err
@ -63,18 +120,31 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error)
}
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 {
if len(s) > 1 {
if s[0:2] == "0x" {
s = s[2:]
}
if len(s)%2 == 1 {
s = "0" + s
}
return ethutil.Hex2Bytes(s)
}
return nil
}
func i2hex(n int) string {
return toHex(big.NewInt(int64(n)).Bytes())
}
type RpcServer interface {
Start()
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)
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 {
// 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 {
stack.push(ethutil.BigFalse)
vmlogger.Debugln(err)
self.Printf("%v").Endl()
} else {
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
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))
}
@ -894,7 +894,7 @@ func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
func (self *Vm) Endl() VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
vmlogger.Debugln(self.logStr)
vmlogger.Infoln(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) UseState(statedb *state.StateDB) *XEth {
func (self *XEth) WithState(statedb *state.StateDB) *XEth {
xeth := &XEth{
eth: self.eth,
blockProcessor: self.blockProcessor,
@ -122,7 +122,14 @@ func (self *XEth) BlockByHash(strHash string) *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 {
return NewBlock(self.chainManager.CurrentBlock())
}
@ -130,13 +137,21 @@ func (self *XEth) BlockByNumber(num int32) *Block {
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 {
if n, ok := v.(int32); ok {
return self.BlockByNumber(n)
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 ...
return self.BlockByNumber(int32(f))
return self.BlockByNumber(int64(f))
}
return nil
@ -278,14 +293,12 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
return toHex(tx.Hash()), nil
}
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
if len(gasStr) == 0 {
gasStr = "100000"
}
if len(gasPriceStr) == 0 {
gasPriceStr = "1"
}
var (
defaultGasPrice = big.NewInt(10000000000000)
defaultGas = big.NewInt(90000)
)
func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
statedb := self.State().State() //self.chainManager.TransState()
msg := callmsg{
from: statedb.GetOrNewStateObject(fromHex(fromStr)),
@ -295,6 +308,14 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
value: ethutil.Big(valueStr),
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()
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)
}
state := self.chainManager.TransState()
state := self.chainManager.TxState()
nonce := state.GetNonce(from)
tx.SetNonce(nonce)