aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/mist/assets/examples/coin.html89
-rw-r--r--cmd/mist/assets/examples/info.html72
-rw-r--r--rpc/args.go43
-rw-r--r--rpc/message.go62
-rw-r--r--rpc/packages.go105
-rw-r--r--xeth/types.go19
-rw-r--r--xeth/world.go2
7 files changed, 351 insertions, 41 deletions
diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html
new file mode 100644
index 000000000..297d7e042
--- /dev/null
+++ b/cmd/mist/assets/examples/coin.html
@@ -0,0 +1,89 @@
+<!doctype>
+<html>
+
+<head>
+<script type="text/javascript" src="../ext/bignumber.min.js"></script>
+<script type="text/javascript" src="../ext/ethereum.js/dist/ethereum.js"></script>
+</head>
+<body>
+
+<h1>JevCoin</h1>
+<div>
+ <strong>Balance</strong>
+ <span id="balance"></strong>
+</div>
+
+<div>
+ <span class="amount">Amount:</span>
+ <input type="text" id="address" style="width:200px">
+ <input type="text" id="amount" style="width:200px">
+ <button onclick="transact()">Send</button>
+</div>
+
+<table width="100%" id="table">
+</table>
+
+</body>
+
+<script type="text/javascript">
+ var web3 = require('web3');
+ var eth = web3.eth;
+
+ web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
+ var desc = [{
+ "name": "balance(address)",
+ "inputs": [{
+ "name": "who",
+ "type": "address"
+ }],
+ "const": true,
+ "outputs": [{
+ "name": "value",
+ "type": "uint256"
+ }]
+ }, {
+ "name": "send(address,uint256)",
+ "inputs": [{
+ "name": "to",
+ "type": "address"
+ }, {
+ "name": "value",
+ "type": "uint256"
+ }],
+ "outputs": []
+ }];
+
+ var code = "0x60056011565b60ae8060356000396000f35b64174876e800600033600160a060020a031660005260205260406000208190555056006001600060e060020a600035048063d0679d34146022578063e3d670d714603457005b602e6004356024356047565b60006000f35b603d600435608d565b8060005260206000f35b80600083600160a060020a0316600052602052604060002090815401908190555080600033600160a060020a031660005260205260406000209081540390819055505050565b6000600082600160a060020a0316600052602052604060002054905091905056";
+ var address = web3.eth.transact({
+ data: code,
+ gasprice: "1000000000000000",
+ gas: "10000",
+ });
+ var contract = web3.eth.contract(address, desc);
+ document.querySelector("#balance").innerHTML = contract.call().balance(eth.coinbase);
+
+ function reflesh() {
+ var table = document.querySelector("#table");
+ table.innerHTML = ""; // clear
+
+ var storage = eth.storageAt(address);
+ for( var item in storage ) {
+ table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>";
+ }
+ }
+
+ function transact() {
+ //var to = "0x"+document.querySelector("#address").value;
+ var to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3";
+ console.log("to "+to);
+ var value = parseInt( document.querySelector("#amount").value );
+ console.log("value "+value);
+
+ contract.transact({gas: "10000", gasPrice: "1000000000000"}).send( to, value );
+ }
+
+ reflesh();
+</script>
+
+</html>
+
diff --git a/cmd/mist/assets/examples/info.html b/cmd/mist/assets/examples/info.html
new file mode 100644
index 000000000..c4df8ea64
--- /dev/null
+++ b/cmd/mist/assets/examples/info.html
@@ -0,0 +1,72 @@
+
+<!doctype>
+<html>
+
+<head>
+<script type="text/javascript" src="../ext/bignumber.min.js"></script>
+<script type="text/javascript" src="../ext/ethereum.js/dist/ethereum.js"></script>
+</head>
+<body>
+ <h1>Info</h1>
+
+ <table width="100%">
+ <tr>
+ <td>Block number</td>
+ <td id="number"></td>
+ </tr>
+
+ <tr>
+ <td>Peer count</td>
+ <td id="peer_count"></td>
+ </tr>
+
+ <tr>
+ <td>Default block</td>
+ <td id="default_block"></td>
+ </tr>
+
+ <tr>
+ <td>Accounts</td>
+ <td id="accounts"></td>
+ </tr>
+
+ <tr>
+ <td>Gas price</td>
+ <td id="gas_price"></td>
+ </tr>
+
+ <tr>
+ <td>Mining</td>
+ <td id="mining"></td>
+ </tr>
+
+ <tr>
+ <td>Listening</td>
+ <td id="listening"></td>
+ </tr>
+
+ <tr>
+ <td>Coinbase</td>
+ <td id="coinbase"></td>
+ </tr>
+ </table>
+</body>
+
+<script type="text/javascript">
+ var web3 = require('web3');
+ var eth = web3.eth;
+
+ web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
+
+ document.querySelector("#number").innerHTML = eth.number;
+ document.querySelector("#coinbase").innerHTML = eth.coinbase
+ document.querySelector("#peer_count").innerHTML = eth.peerCount;
+ document.querySelector("#default_block").innerHTML = eth.defaultBlock;
+ document.querySelector("#accounts").innerHTML = eth.accounts;
+ document.querySelector("#gas_price").innerHTML = eth.gasPrice;
+ document.querySelector("#mining").innerHTML = eth.mining;
+ document.querySelector("#listening").innerHTML = eth.listening;
+</script>
+
+</html>
+
diff --git a/rpc/args.go b/rpc/args.go
index 79519e7d2..aaa017c4e 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -69,10 +69,28 @@ func (a *PushTxArgs) requirementsPushTx() error {
type GetStorageArgs struct {
Address string
- Key string
}
func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
+ if err = json.Unmarshal(b, &obj.Address); err != nil {
+ return NewErrorResponse(ErrorDecodeArgs)
+ }
+ return
+}
+
+func (a *GetStorageArgs) requirements() error {
+ if len(a.Address) == 0 {
+ return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
+ }
+ return nil
+}
+
+type GetStateArgs struct {
+ Address string
+ Key string
+}
+
+func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) {
arg0 := ""
if err = json.Unmarshal(b, arg0); err == nil {
obj.Address = arg0
@@ -81,7 +99,7 @@ func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
return NewErrorResponse(ErrorDecodeArgs)
}
-func (a *GetStorageArgs) requirements() error {
+func (a *GetStateArgs) requirements() error {
if a.Address == "" {
return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
}
@@ -92,9 +110,8 @@ func (a *GetStorageArgs) requirements() error {
}
type GetStorageAtRes struct {
- Key string `json:"key"`
- Value string `json:"value"`
- Address string `json:"address"`
+ Key string `json:"key"`
+ Value string `json:"value"`
}
type GetTxCountArgs struct {
@@ -218,3 +235,19 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions {
type FilterChangedArgs struct {
n int
}
+
+type DbArgs struct {
+ Database string
+ Key string
+ Value string
+}
+
+func (a *DbArgs) requirements() error {
+ if len(a.Database) == 0 {
+ return NewErrorResponse("DbPutArgs requires an 'Database' value as argument")
+ }
+ if len(a.Key) == 0 {
+ return NewErrorResponse("DbPutArgs requires an 'Key' value as argument")
+ }
+ return nil
+}
diff --git a/rpc/message.go b/rpc/message.go
index 05f66ee95..a76eaece4 100644
--- a/rpc/message.go
+++ b/rpc/message.go
@@ -126,12 +126,12 @@ func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) {
return args, nil
}
-func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) {
- if len(req.Params) < 2 {
+func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) {
+ if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
}
- args := new(GetStorageArgs)
+ args := new(GetStateArgs)
// TODO need to pass both arguments
r := bytes.NewReader(req.Params[0])
err := json.NewDecoder(r).Decode(args)
@@ -142,6 +142,21 @@ func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) {
return args, nil
}
+func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(GetStorageArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ rpclogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) {
if len(req.Params) < 1 {
return nil, NewErrorResponse(ErrorArguments)
@@ -239,3 +254,44 @@ func toLogs(logs state.Logs) (ls []Log) {
return
}
+
+func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) {
+ if len(req.Params) < 3 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ var args DbArgs
+ err := json.Unmarshal(req.Params[0], &args.Database)
+ if err != nil {
+ return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
+ }
+ err = json.Unmarshal(req.Params[1], &args.Key)
+ if err != nil {
+ return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
+ }
+ err = json.Unmarshal(req.Params[2], &args.Value)
+ if err != nil {
+ return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
+ }
+ rpclogger.DebugDetailf("%T %v", args, args)
+ return &args, nil
+}
+
+func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) {
+ if len(req.Params) < 2 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ var args DbArgs
+ err := json.Unmarshal(req.Params[0], &args.Database)
+ if err != nil {
+ return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
+ }
+
+ err = json.Unmarshal(req.Params[1], &args.Key)
+ if err != nil {
+ return nil, NewErrorResponseWithError(ErrorDecodeArgs, err)
+ }
+ rpclogger.DebugDetailf("%T %v", args, args)
+ return &args, nil
+}
diff --git a/rpc/packages.go b/rpc/packages.go
index e8dc570fd..2de1f06cd 100644
--- a/rpc/packages.go
+++ b/rpc/packages.go
@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event/filter"
"github.com/ethereum/go-ethereum/state"
@@ -63,13 +64,17 @@ type EthereumApi struct {
mut sync.RWMutex
logs map[int]state.Logs
+
+ db ethutil.Database
}
func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
+ db, _ := ethdb.NewLDBDatabase("dapps")
api := &EthereumApi{
xeth: xeth,
filterManager: filter.NewFilterManager(xeth.Backend().EventMux()),
logs: make(map[int]state.Logs),
+ db: db,
}
go api.filterManager.Start()
@@ -91,29 +96,6 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro
return nil
}
-type Log struct {
- Address string `json:"address"`
- Topics []string `json:"topics"`
- Data string `json:"data"`
-}
-
-func toLogs(logs state.Logs) (ls []Log) {
- ls = make([]Log, len(logs))
-
- for i, log := range logs {
- var l Log
- l.Topics = make([]string, len(log.Topics()))
- l.Address = toHex(log.Address())
- l.Data = toHex(log.Data())
- for j, topic := range log.Topics() {
- l.Topics[j] = toHex(topic)
- }
- ls[i] = l
- }
-
- return
-}
-
func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error {
self.mut.RLock()
defer self.mut.RUnlock()
@@ -176,7 +158,7 @@ func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
return nil
}
-func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
+func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
@@ -184,6 +166,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err
state := p.xeth.State().SafeGet(args.Address)
+ value := state.StorageString(args.Key)
var hx string
if strings.Index(args.Key, "0x") == 0 {
hx = string([]byte(args.Key)[2:])
@@ -192,9 +175,18 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err
i, _ := new(big.Int).SetString(args.Key, 10)
hx = ethutil.Bytes2Hex(i.Bytes())
}
- rpclogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
- value := state.Storage(ethutil.Hex2Bytes(hx))
- *reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
+ rpclogger.Debugf("GetStateAt(%s, %s)\n", args.Address, hx)
+ *reply = map[string]string{args.Key: value.Str()}
+ 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
}
@@ -213,11 +205,21 @@ func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
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) 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 {
@@ -251,6 +253,28 @@ func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error {
return nil
}
+func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
+ err := args.requirements()
+ if err != nil {
+ return err
+ }
+
+ p.db.Put([]byte(args.Database+args.Key), []byte(args.Value))
+ *reply = true
+ return nil
+}
+
+func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
+ err := args.requirements()
+ if err != nil {
+ return err
+ }
+
+ res, _ := p.db.Get([]byte(args.Database + args.Key))
+ *reply = string(res)
+ return nil
+}
+
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC
rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
@@ -263,6 +287,10 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return p.GetIsMining(reply)
case "eth_peerCount":
return p.GetPeerCount(reply)
+ case "eth_number":
+ return p.BlockNumber(reply)
+ case "eth_accounts":
+ return p.Accounts(reply)
case "eth_countAt":
args, err := req.ToGetTxCountArgs()
if err != nil {
@@ -282,7 +310,13 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
}
return p.GetBalanceAt(args, reply)
case "eth_stateAt":
- args, err := req.ToGetStorageArgs()
+ 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
}
@@ -317,12 +351,27 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err
}
return p.FilterChanged(args, reply)
+ case "eth_gasPrice":
+ *reply = "1000000000000000"
+ return nil
case "web3_sha3":
args, err := req.ToSha3Args()
if err != nil {
return err
}
return p.Sha3(args, reply)
+ case "db_put":
+ args, err := req.ToDbPutArgs()
+ if err != nil {
+ return err
+ }
+ return p.DbPut(args, reply)
+ case "db_get":
+ args, err := req.ToDbGetArgs()
+ if err != nil {
+ return err
+ }
+ return p.DbGet(args, reply)
default:
return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method))
}
diff --git a/xeth/types.go b/xeth/types.go
index 4d8543eb1..bee730ba1 100644
--- a/xeth/types.go
+++ b/xeth/types.go
@@ -35,20 +35,31 @@ func NewObject(state *state.StateObject) *Object {
func (self *Object) StorageString(str string) *ethutil.Value {
if ethutil.IsHex(str) {
- return self.Storage(ethutil.Hex2Bytes(str[2:]))
+ return self.storage(ethutil.Hex2Bytes(str[2:]))
} else {
- return self.Storage(ethutil.RightPadBytes([]byte(str), 32))
+ return self.storage(ethutil.RightPadBytes([]byte(str), 32))
}
}
func (self *Object) StorageValue(addr *ethutil.Value) *ethutil.Value {
- return self.Storage(addr.Bytes())
+ return self.storage(addr.Bytes())
}
-func (self *Object) Storage(addr []byte) *ethutil.Value {
+func (self *Object) storage(addr []byte) *ethutil.Value {
return self.StateObject.GetStorage(ethutil.BigD(addr))
}
+func (self *Object) Storage() (storage map[string]string) {
+ storage = make(map[string]string)
+
+ it := self.StateObject.Trie().Iterator()
+ for it.Next() {
+ storage[toHex(it.Key)] = toHex(it.Value)
+ }
+
+ return
+}
+
// Block interface exposed to QML
type Block struct {
//Transactions string `json:"transactions"`
diff --git a/xeth/world.go b/xeth/world.go
index cdceec50d..9cbdd9461 100644
--- a/xeth/world.go
+++ b/xeth/world.go
@@ -11,7 +11,7 @@ func NewState(xeth *XEth) *State {
}
func (self *State) State() *state.StateDB {
- return self.xeth.chainManager.State()
+ return self.xeth.chainManager.TransState()
}
func (self *State) Get(addr string) *Object {