Merge branch 'hexify' of https://github.com/tgerring/go-ethereum into tgerring-hexify
This commit is contained in:
		| @@ -233,8 +233,9 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big | |||||||
| 		sm.txpool.RemoveSet(block.Transactions()) | 		sm.txpool.RemoveSet(block.Transactions()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, tx := range block.Transactions() { | 	// This puts transactions in a extra db for rpc | ||||||
| 		putTx(sm.extraDb, tx) | 	for i, tx := range block.Transactions() { | ||||||
|  | 		putTx(sm.extraDb, tx, block, uint64(i)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if uncle { | 	if uncle { | ||||||
| @@ -362,11 +363,26 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro | |||||||
| 	return state.Logs(), nil | 	return state.Logs(), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func putTx(db common.Database, tx *types.Transaction) { | func putTx(db common.Database, tx *types.Transaction, block *types.Block, i uint64) { | ||||||
| 	rlpEnc, err := rlp.EncodeToBytes(tx) | 	rlpEnc, err := rlp.EncodeToBytes(tx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		statelogger.Infoln("Failed encoding tx", err) | 		statelogger.Infoln("Failed encoding tx", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	db.Put(tx.Hash().Bytes(), rlpEnc) | 	db.Put(tx.Hash().Bytes(), rlpEnc) | ||||||
|  |  | ||||||
|  | 	var txExtra struct { | ||||||
|  | 		BlockHash  common.Hash | ||||||
|  | 		BlockIndex uint64 | ||||||
|  | 		Index      uint64 | ||||||
|  | 	} | ||||||
|  | 	txExtra.BlockHash = block.Hash() | ||||||
|  | 	txExtra.BlockIndex = block.NumberU64() | ||||||
|  | 	txExtra.Index = i | ||||||
|  | 	rlpMeta, err := rlp.EncodeToBytes(txExtra) | ||||||
|  | 	if err != nil { | ||||||
|  | 		statelogger.Infoln("Failed encoding meta", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								rpc/api.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								rpc/api.go
									
									
									
									
									
								
							| @@ -54,7 +54,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 	case "net_peerCount": | 	case "net_peerCount": | ||||||
| 		v := api.xeth().PeerCount() | 		v := api.xeth().PeerCount() | ||||||
| 		*reply = common.ToHex(big.NewInt(int64(v)).Bytes()) | 		*reply = common.ToHex(big.NewInt(int64(v)).Bytes()) | ||||||
| 	case "eth_version": | 	case "eth_protocolVersion": | ||||||
| 		*reply = api.xeth().EthVersion() | 		*reply = api.xeth().EthVersion() | ||||||
| 	case "eth_coinbase": | 	case "eth_coinbase": | ||||||
| 		// TODO handling of empty coinbase due to lack of accounts | 		// TODO handling of empty coinbase due to lack of accounts | ||||||
| @@ -159,7 +159,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 		} | 		} | ||||||
| 		*reply = v | 		*reply = v | ||||||
| 	case "eth_call": | 	case "eth_call": | ||||||
| 		args := new(NewTxArgs) | 		args := new(CallArgs) | ||||||
| 		if err := json.Unmarshal(req.Params, &args); err != nil { | 		if err := json.Unmarshal(req.Params, &args); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @@ -199,9 +199,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 		args := new(HashIndexArgs) | 		args := new(HashIndexArgs) | ||||||
| 		if err := json.Unmarshal(req.Params, &args); err != nil { | 		if err := json.Unmarshal(req.Params, &args); err != nil { | ||||||
| 		} | 		} | ||||||
| 		tx := api.xeth().EthTransactionByHash(args.Hash) | 		tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash) | ||||||
| 		if tx != nil { | 		if tx != nil { | ||||||
| 			*reply = NewTransactionRes(tx) | 			v := NewTransactionRes(tx) | ||||||
|  | 			v.BlockHash = newHexData(bhash) | ||||||
|  | 			v.BlockNumber = newHexNum(bnum) | ||||||
|  | 			v.TxIndex = newHexNum(txi) | ||||||
|  | 			*reply = v | ||||||
| 		} | 		} | ||||||
| 	case "eth_getTransactionByBlockHashAndIndex": | 	case "eth_getTransactionByBlockHashAndIndex": | ||||||
| 		args := new(HashIndexArgs) | 		args := new(HashIndexArgs) | ||||||
| @@ -213,7 +217,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 		br := NewBlockRes(block) | 		br := NewBlockRes(block) | ||||||
| 		br.fullTx = true | 		br.fullTx = true | ||||||
|  |  | ||||||
| 		if args.Index > int64(len(br.Transactions)) || args.Index < 0 { | 		if args.Index >= int64(len(br.Transactions)) || args.Index < 0 { | ||||||
| 			return NewValidationError("Index", "does not exist") | 			return NewValidationError("Index", "does not exist") | ||||||
| 		} | 		} | ||||||
| 		*reply = br.Transactions[args.Index] | 		*reply = br.Transactions[args.Index] | ||||||
| @@ -227,7 +231,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 		v := NewBlockRes(block) | 		v := NewBlockRes(block) | ||||||
| 		v.fullTx = true | 		v.fullTx = true | ||||||
|  |  | ||||||
| 		if args.Index > int64(len(v.Transactions)) || args.Index < 0 { | 		if args.Index >= int64(len(v.Transactions)) || args.Index < 0 { | ||||||
| 			return NewValidationError("Index", "does not exist") | 			return NewValidationError("Index", "does not exist") | ||||||
| 		} | 		} | ||||||
| 		*reply = v.Transactions[args.Index] | 		*reply = v.Transactions[args.Index] | ||||||
| @@ -239,12 +243,12 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
|  |  | ||||||
| 		br := NewBlockRes(api.xeth().EthBlockByHash(args.Hash)) | 		br := NewBlockRes(api.xeth().EthBlockByHash(args.Hash)) | ||||||
|  |  | ||||||
| 		if args.Index > int64(len(br.Uncles)) || args.Index < 0 { | 		if args.Index >= int64(len(br.Uncles)) || args.Index < 0 { | ||||||
| 			return NewValidationError("Index", "does not exist") | 			return NewValidationError("Index", "does not exist") | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		uhash := br.Uncles[args.Index] | 		uhash := br.Uncles[args.Index] | ||||||
| 		uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.Hex())) | 		uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String())) | ||||||
|  |  | ||||||
| 		*reply = uncle | 		*reply = uncle | ||||||
| 	case "eth_getUncleByBlockNumberAndIndex": | 	case "eth_getUncleByBlockNumberAndIndex": | ||||||
| @@ -257,12 +261,12 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err | |||||||
| 		v := NewBlockRes(block) | 		v := NewBlockRes(block) | ||||||
| 		v.fullTx = true | 		v.fullTx = true | ||||||
|  |  | ||||||
| 		if args.Index > int64(len(v.Uncles)) || args.Index < 0 { | 		if args.Index >= int64(len(v.Uncles)) || args.Index < 0 { | ||||||
| 			return NewValidationError("Index", "does not exist") | 			return NewValidationError("Index", "does not exist") | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		uhash := v.Uncles[args.Index] | 		uhash := v.Uncles[args.Index] | ||||||
| 		uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.Hex())) | 		uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String())) | ||||||
|  |  | ||||||
| 		*reply = uncle | 		*reply = uncle | ||||||
| 	case "eth_getCompilers": | 	case "eth_getCompilers": | ||||||
|   | |||||||
							
								
								
									
										87
									
								
								rpc/args.go
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								rpc/args.go
									
									
									
									
									
								
							| @@ -238,6 +238,93 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type CallArgs struct { | ||||||
|  | 	From     string | ||||||
|  | 	To       string | ||||||
|  | 	Value    *big.Int | ||||||
|  | 	Gas      *big.Int | ||||||
|  | 	GasPrice *big.Int | ||||||
|  | 	Data     string | ||||||
|  |  | ||||||
|  | 	BlockNumber int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (args *CallArgs) UnmarshalJSON(b []byte) (err error) { | ||||||
|  | 	var obj []json.RawMessage | ||||||
|  | 	var ext struct { | ||||||
|  | 		From     string | ||||||
|  | 		To       string | ||||||
|  | 		Value    interface{} | ||||||
|  | 		Gas      interface{} | ||||||
|  | 		GasPrice interface{} | ||||||
|  | 		Data     string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Decode byte slice to array of RawMessages | ||||||
|  | 	if err := json.Unmarshal(b, &obj); err != nil { | ||||||
|  | 		return NewDecodeParamError(err.Error()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Check for sufficient params | ||||||
|  | 	if len(obj) < 1 { | ||||||
|  | 		return NewInsufficientParamsError(len(obj), 1) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Decode 0th RawMessage to temporary struct | ||||||
|  | 	if err := json.Unmarshal(obj[0], &ext); err != nil { | ||||||
|  | 		return NewDecodeParamError(err.Error()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(ext.From) == 0 { | ||||||
|  | 		return NewValidationError("from", "is required") | ||||||
|  | 	} | ||||||
|  | 	args.From = ext.From | ||||||
|  |  | ||||||
|  | 	if len(ext.To) == 0 { | ||||||
|  | 		return NewValidationError("to", "is required") | ||||||
|  | 	} | ||||||
|  | 	args.To = ext.To | ||||||
|  |  | ||||||
|  | 	var num int64 | ||||||
|  | 	if ext.Value == nil { | ||||||
|  | 		num = int64(0) | ||||||
|  | 	} else { | ||||||
|  | 		if err := numString(ext.Value, &num); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	args.Value = big.NewInt(num) | ||||||
|  |  | ||||||
|  | 	if ext.Gas == nil { | ||||||
|  | 		num = int64(0) | ||||||
|  | 	} else { | ||||||
|  | 		if err := numString(ext.Gas, &num); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	args.Gas = big.NewInt(num) | ||||||
|  |  | ||||||
|  | 	if ext.GasPrice == nil { | ||||||
|  | 		num = int64(0) | ||||||
|  | 	} else { | ||||||
|  | 		if err := numString(ext.GasPrice, &num); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	args.GasPrice = big.NewInt(num) | ||||||
|  |  | ||||||
|  | 	args.Data = ext.Data | ||||||
|  |  | ||||||
|  | 	// Check for optional BlockNumber param | ||||||
|  | 	if len(obj) > 1 { | ||||||
|  | 		if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| type GetStorageArgs struct { | type GetStorageArgs struct { | ||||||
| 	Address     string | 	Address     string | ||||||
| 	BlockNumber int64 | 	BlockNumber int64 | ||||||
|   | |||||||
							
								
								
									
										277
									
								
								rpc/args_test.go
									
									
									
									
									
								
							
							
						
						
									
										277
									
								
								rpc/args_test.go
									
									
									
									
									
								
							| @@ -531,14 +531,275 @@ func TestNewTxArgsFromEmpty(t *testing.T) { | |||||||
| 	input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` | 	input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` | ||||||
|  |  | ||||||
| 	args := new(NewTxArgs) | 	args := new(NewTxArgs) | ||||||
| 	err := json.Unmarshal([]byte(input), &args) | 	str := ExpectValidationError(json.Unmarshal([]byte(input), &args)) | ||||||
| 	switch err.(type) { | 	if len(str) > 0 { | ||||||
| 	case nil: | 		t.Error(str) | ||||||
| 		t.Error("Expected error but didn't get one") | 	} | ||||||
| 	case *ValidationError: | } | ||||||
| 		break |  | ||||||
| 	default: | func TestCallArgs(t *testing.T) { | ||||||
| 		t.Errorf("Expected *rpc.ValidationError, but got %T with message `%s`", err, err.Error()) | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, | ||||||
|  |   "0x10"]` | ||||||
|  | 	expected := new(CallArgs) | ||||||
|  | 	expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" | ||||||
|  | 	expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675" | ||||||
|  | 	expected.Gas = big.NewInt(30400) | ||||||
|  | 	expected.GasPrice = big.NewInt(10000000000000) | ||||||
|  | 	expected.Value = big.NewInt(10000000000000) | ||||||
|  | 	expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  | 	expected.BlockNumber = big.NewInt(16).Int64() | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if expected.BlockNumber != args.BlockNumber { | ||||||
|  | 		t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsInt(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": 100, | ||||||
|  |   "gasPrice": 50, | ||||||
|  |   "value": 8765456789, | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, | ||||||
|  |   5]` | ||||||
|  | 	expected := new(CallArgs) | ||||||
|  | 	expected.Gas = big.NewInt(100) | ||||||
|  | 	expected.GasPrice = big.NewInt(50) | ||||||
|  | 	expected.Value = big.NewInt(8765456789) | ||||||
|  | 	expected.BlockNumber = int64(5) | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	if err := json.Unmarshal([]byte(input), &args); err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { | ||||||
|  | 		t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	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.BlockNumber != args.BlockNumber { | ||||||
|  | 		t.Errorf("BlockNumber shoud be %v but is %v", expected.BlockNumber, args.BlockNumber) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsBlockBool(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, | ||||||
|  |   false]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsGasInvalid(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": false, | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  |   }]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsGaspriceInvalid(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "gasPrice": false, | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  |   }]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsValueInvalid(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "value": false, | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  | 	}]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsGasMissing(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  |   }]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	if err := json.Unmarshal([]byte(input), &args); err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	expected := new(CallArgs) | ||||||
|  | 	expected.Gas = big.NewInt(0) | ||||||
|  |  | ||||||
|  | 	if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { | ||||||
|  | 		t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsBlockGaspriceMissing(t *testing.T) { | ||||||
|  | 	input := `[{ | ||||||
|  | 	"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "value": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  |   }]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	if err := json.Unmarshal([]byte(input), &args); err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	expected := new(CallArgs) | ||||||
|  | 	expected.GasPrice = big.NewInt(0) | ||||||
|  |  | ||||||
|  | 	if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { | ||||||
|  | 		t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsValueMissing(t *testing.T) { | ||||||
|  | 	input := `[{ | ||||||
|  | 	"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", | ||||||
|  |   "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", | ||||||
|  |   "gas": "0x76c0", | ||||||
|  |   "gasPrice": "0x9184e72a000", | ||||||
|  |   "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" | ||||||
|  | 	}]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	if err := json.Unmarshal([]byte(input), &args); err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	expected := new(CallArgs) | ||||||
|  | 	expected.Value = big.NewInt(int64(0)) | ||||||
|  |  | ||||||
|  | 	if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { | ||||||
|  | 		t.Errorf("GasPrice shoud be %v but is %v", expected.Value, args.Value) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsEmpty(t *testing.T) { | ||||||
|  | 	input := `[]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsInvalid(t *testing.T) { | ||||||
|  | 	input := `{}` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func TestCallArgsNotStrings(t *testing.T) { | ||||||
|  | 	input := `[{"from":6}]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsFromEmpty(t *testing.T) { | ||||||
|  | 	input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectValidationError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCallArgsToEmpty(t *testing.T) { | ||||||
|  | 	input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` | ||||||
|  |  | ||||||
|  | 	args := new(CallArgs) | ||||||
|  | 	str := ExpectValidationError(json.Unmarshal([]byte(input), &args)) | ||||||
|  | 	if len(str) > 0 { | ||||||
|  | 		t.Error(str) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,8 +19,95 @@ package rpc | |||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"math/big" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type hexdata struct { | ||||||
|  | 	data []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexdata) String() string { | ||||||
|  | 	return "0x" + common.Bytes2Hex(d.data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexdata) MarshalJSON() ([]byte, error) { | ||||||
|  | 	return json.Marshal(d.String()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexdata) UnmarshalJSON(b []byte) (err error) { | ||||||
|  | 	d.data = common.FromHex(string(b)) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newHexData(input interface{}) *hexdata { | ||||||
|  | 	d := new(hexdata) | ||||||
|  |  | ||||||
|  | 	switch input := input.(type) { | ||||||
|  | 	case []byte: | ||||||
|  | 		d.data = input | ||||||
|  | 	case common.Hash: | ||||||
|  | 		d.data = input.Bytes() | ||||||
|  | 	case *common.Hash: | ||||||
|  | 		d.data = input.Bytes() | ||||||
|  | 	case common.Address: | ||||||
|  | 		d.data = input.Bytes() | ||||||
|  | 	case *common.Address: | ||||||
|  | 		d.data = input.Bytes() | ||||||
|  | 	case *big.Int: | ||||||
|  | 		d.data = input.Bytes() | ||||||
|  | 	case int64: | ||||||
|  | 		d.data = big.NewInt(input).Bytes() | ||||||
|  | 	case uint64: | ||||||
|  | 		d.data = big.NewInt(int64(input)).Bytes() | ||||||
|  | 	case int: | ||||||
|  | 		d.data = big.NewInt(int64(input)).Bytes() | ||||||
|  | 	case uint: | ||||||
|  | 		d.data = big.NewInt(int64(input)).Bytes() | ||||||
|  | 	case string: // hexstring | ||||||
|  | 		d.data = common.Big(input).Bytes() | ||||||
|  | 	default: | ||||||
|  | 		d.data = nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return d | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hexnum struct { | ||||||
|  | 	data []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexnum) String() string { | ||||||
|  | 	// Get hex string from bytes | ||||||
|  | 	out := common.Bytes2Hex(d.data) | ||||||
|  | 	// Trim leading 0s | ||||||
|  | 	out = strings.Trim(out, "0") | ||||||
|  | 	// Output "0x0" when value is 0 | ||||||
|  | 	if len(out) == 0 { | ||||||
|  | 		out = "0" | ||||||
|  | 	} | ||||||
|  | 	return "0x" + out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexnum) MarshalJSON() ([]byte, error) { | ||||||
|  | 	return json.Marshal(d.String()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *hexnum) UnmarshalJSON(b []byte) (err error) { | ||||||
|  | 	d.data = common.FromHex(string(b)) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newHexNum(input interface{}) *hexnum { | ||||||
|  | 	d := new(hexnum) | ||||||
|  |  | ||||||
|  | 	d.data = newHexData(input).data | ||||||
|  |  | ||||||
|  | 	return d | ||||||
|  | } | ||||||
|  |  | ||||||
| type InvalidTypeError struct { | type InvalidTypeError struct { | ||||||
| 	method string | 	method string | ||||||
| 	msg    string | 	msg    string | ||||||
|   | |||||||
							
								
								
									
										312
									
								
								rpc/responses.go
									
									
									
									
									
								
							
							
						
						
									
										312
									
								
								rpc/responses.go
									
									
									
									
									
								
							| @@ -1,11 +1,6 @@ | |||||||
| package rpc | package rpc | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" |  | ||||||
| 	// "fmt" |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core/state" | 	"github.com/ethereum/go-ethereum/core/state" | ||||||
| 	"github.com/ethereum/go-ethereum/core/types" | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| ) | ) | ||||||
| @@ -13,84 +8,25 @@ import ( | |||||||
| type BlockRes struct { | type BlockRes struct { | ||||||
| 	fullTx bool | 	fullTx bool | ||||||
|  |  | ||||||
| 	BlockNumber     *big.Int          `json:"number"` | 	BlockNumber     *hexnum           `json:"number"` | ||||||
| 	BlockHash       common.Hash       `json:"hash"` | 	BlockHash       *hexdata          `json:"hash"` | ||||||
| 	ParentHash      common.Hash       `json:"parentHash"` | 	ParentHash      *hexdata          `json:"parentHash"` | ||||||
| 	Nonce           [8]byte           `json:"nonce"` | 	Nonce           *hexnum           `json:"nonce"` | ||||||
| 	Sha3Uncles      common.Hash       `json:"sha3Uncles"` | 	Sha3Uncles      *hexdata          `json:"sha3Uncles"` | ||||||
| 	LogsBloom       types.Bloom       `json:"logsBloom"` | 	LogsBloom       *hexdata          `json:"logsBloom"` | ||||||
| 	TransactionRoot common.Hash       `json:"transactionRoot"` | 	TransactionRoot *hexdata          `json:"transactionRoot"` | ||||||
| 	StateRoot       common.Hash       `json:"stateRoot"` | 	StateRoot       *hexdata          `json:"stateRoot"` | ||||||
| 	Miner           common.Address    `json:"miner"` | 	Miner           *hexdata          `json:"miner"` | ||||||
| 	Difficulty      *big.Int          `json:"difficulty"` | 	Difficulty      *hexnum           `json:"difficulty"` | ||||||
| 	TotalDifficulty *big.Int          `json:"totalDifficulty"` | 	TotalDifficulty *hexnum           `json:"totalDifficulty"` | ||||||
| 	Size            *big.Int          `json:"size"` | 	Size            *hexnum           `json:"size"` | ||||||
| 	ExtraData       []byte            `json:"extraData"` | 	ExtraData       *hexdata          `json:"extraData"` | ||||||
| 	GasLimit        *big.Int          `json:"gasLimit"` | 	GasLimit        *hexnum           `json:"gasLimit"` | ||||||
| 	MinGasPrice     int64             `json:"minGasPrice"` | 	MinGasPrice     *hexnum           `json:"minGasPrice"` | ||||||
| 	GasUsed         *big.Int          `json:"gasUsed"` | 	GasUsed         *hexnum           `json:"gasUsed"` | ||||||
| 	UnixTimestamp   int64             `json:"timestamp"` | 	UnixTimestamp   *hexnum           `json:"timestamp"` | ||||||
| 	Transactions    []*TransactionRes `json:"transactions"` | 	Transactions    []*TransactionRes `json:"transactions"` | ||||||
| 	Uncles          []common.Hash     `json:"uncles"` | 	Uncles          []*hexdata        `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 = common.ToHex(b.BlockNumber.Bytes()) |  | ||||||
| 	ext.BlockHash = b.BlockHash.Hex() |  | ||||||
| 	ext.ParentHash = b.ParentHash.Hex() |  | ||||||
| 	ext.Nonce = common.ToHex(b.Nonce[:]) |  | ||||||
| 	ext.Sha3Uncles = b.Sha3Uncles.Hex() |  | ||||||
| 	ext.LogsBloom = common.ToHex(b.LogsBloom[:]) |  | ||||||
| 	ext.TransactionRoot = b.TransactionRoot.Hex() |  | ||||||
| 	ext.StateRoot = b.StateRoot.Hex() |  | ||||||
| 	ext.Miner = b.Miner.Hex() |  | ||||||
| 	ext.Difficulty = common.ToHex(b.Difficulty.Bytes()) |  | ||||||
| 	ext.TotalDifficulty = common.ToHex(b.TotalDifficulty.Bytes()) |  | ||||||
| 	ext.Size = common.ToHex(b.Size.Bytes()) |  | ||||||
| 	ext.ExtraData = common.ToHex(b.ExtraData) |  | ||||||
| 	ext.GasLimit = common.ToHex(b.GasLimit.Bytes()) |  | ||||||
| 	// ext.MinGasPrice = common.ToHex(big.NewInt(b.MinGasPrice).Bytes()) |  | ||||||
| 	ext.GasUsed = common.ToHex(b.GasUsed.Bytes()) |  | ||||||
| 	ext.UnixTimestamp = common.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] = tx.Hash.Hex() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	ext.Uncles = make([]string, len(b.Uncles)) |  | ||||||
| 	for i, v := range b.Uncles { |  | ||||||
| 		ext.Uncles[i] = v.Hex() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return json.Marshal(ext) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewBlockRes(block *types.Block) *BlockRes { | func NewBlockRes(block *types.Block) *BlockRes { | ||||||
| @@ -99,160 +35,118 @@ func NewBlockRes(block *types.Block) *BlockRes { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	res := new(BlockRes) | 	res := new(BlockRes) | ||||||
| 	res.BlockNumber = block.Number() | 	res.BlockNumber = newHexNum(block.Number()) | ||||||
| 	res.BlockHash = block.Hash() | 	res.BlockHash = newHexData(block.Hash()) | ||||||
| 	res.ParentHash = block.ParentHash() | 	res.ParentHash = newHexData(block.ParentHash()) | ||||||
| 	res.Nonce = block.Header().Nonce | 	res.Nonce = newHexNum(block.Header().Nonce) | ||||||
| 	res.Sha3Uncles = block.Header().UncleHash | 	res.Sha3Uncles = newHexData(block.Header().UncleHash) | ||||||
| 	res.LogsBloom = block.Bloom() | 	res.LogsBloom = newHexData(block.Bloom()) | ||||||
| 	res.TransactionRoot = block.Header().TxHash | 	res.TransactionRoot = newHexData(block.Header().TxHash) | ||||||
| 	res.StateRoot = block.Root() | 	res.StateRoot = newHexData(block.Root()) | ||||||
| 	res.Miner = block.Header().Coinbase | 	res.Miner = newHexData(block.Header().Coinbase) | ||||||
| 	res.Difficulty = block.Difficulty() | 	res.Difficulty = newHexNum(block.Difficulty()) | ||||||
| 	res.TotalDifficulty = block.Td | 	res.TotalDifficulty = newHexNum(block.Td) | ||||||
| 	res.Size = big.NewInt(int64(block.Size())) | 	res.Size = newHexNum(block.Size()) | ||||||
| 	res.ExtraData = []byte(block.Header().Extra) | 	res.ExtraData = newHexData(block.Header().Extra) | ||||||
| 	res.GasLimit = block.GasLimit() | 	res.GasLimit = newHexNum(block.GasLimit()) | ||||||
| 	// res.MinGasPrice = | 	// res.MinGasPrice = | ||||||
| 	res.GasUsed = block.GasUsed() | 	res.GasUsed = newHexNum(block.GasUsed()) | ||||||
| 	res.UnixTimestamp = block.Time() | 	res.UnixTimestamp = newHexNum(block.Time()) | ||||||
| 	res.Transactions = make([]*TransactionRes, len(block.Transactions())) | 	res.Transactions = NewTransactionsRes(block.Transactions()) | ||||||
| 	for i, tx := range block.Transactions() { | 	res.Uncles = make([]*hexdata, len(block.Uncles())) | ||||||
| 		v := NewTransactionRes(tx) |  | ||||||
| 		v.BlockHash = block.Hash() |  | ||||||
| 		v.BlockNumber = block.Number().Int64() |  | ||||||
| 		v.TxIndex = int64(i) |  | ||||||
| 		res.Transactions[i] = v |  | ||||||
| 	} |  | ||||||
| 	res.Uncles = make([]common.Hash, len(block.Uncles())) |  | ||||||
| 	for i, uncle := range block.Uncles() { | 	for i, uncle := range block.Uncles() { | ||||||
| 		res.Uncles[i] = uncle.Hash() | 		res.Uncles[i] = newHexData(uncle.Hash()) | ||||||
| 	} | 	} | ||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
|  |  | ||||||
| type TransactionRes struct { | type TransactionRes struct { | ||||||
| 	Hash        common.Hash     `json:"hash"` | 	Hash        *hexdata `json:"hash"` | ||||||
| 	Nonce       uint64          `json:"nonce"` | 	Nonce       *hexnum  `json:"nonce"` | ||||||
| 	BlockHash   common.Hash     `json:"blockHash,omitempty"` | 	BlockHash   *hexdata `json:"blockHash"` | ||||||
| 	BlockNumber int64           `json:"blockNumber,omitempty"` | 	BlockNumber *hexnum  `json:"blockNumber"` | ||||||
| 	TxIndex     int64           `json:"transactionIndex,omitempty"` | 	TxIndex     *hexnum  `json:"transactionIndex"` | ||||||
| 	From        common.Address  `json:"from"` | 	From        *hexdata `json:"from"` | ||||||
| 	To          *common.Address `json:"to"` | 	To          *hexdata `json:"to"` | ||||||
| 	Value       *big.Int        `json:"value"` | 	Value       *hexnum  `json:"value"` | ||||||
| 	Gas         *big.Int        `json:"gas"` | 	Gas         *hexnum  `json:"gas"` | ||||||
| 	GasPrice    *big.Int        `json:"gasPrice"` | 	GasPrice    *hexnum  `json:"gasPrice"` | ||||||
| 	Input       []byte          `json:"input"` | 	Input       *hexdata `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          interface{} `json:"to"` |  | ||||||
| 		Value       string      `json:"value"` |  | ||||||
| 		Gas         string      `json:"gas"` |  | ||||||
| 		GasPrice    string      `json:"gasPrice"` |  | ||||||
| 		Input       string      `json:"input"` |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ext.Hash = t.Hash.Hex() |  | ||||||
| 	ext.Nonce = common.ToHex(big.NewInt(int64(t.Nonce)).Bytes()) |  | ||||||
| 	ext.BlockHash = t.BlockHash.Hex() |  | ||||||
| 	ext.BlockNumber = common.ToHex(big.NewInt(t.BlockNumber).Bytes()) |  | ||||||
| 	ext.TxIndex = common.ToHex(big.NewInt(t.TxIndex).Bytes()) |  | ||||||
| 	ext.From = t.From.Hex() |  | ||||||
| 	if t.To == nil { |  | ||||||
| 		ext.To = nil |  | ||||||
| 	} else { |  | ||||||
| 		ext.To = t.To.Hex() |  | ||||||
| 	} |  | ||||||
| 	ext.Value = common.ToHex(t.Value.Bytes()) |  | ||||||
| 	ext.Gas = common.ToHex(t.Gas.Bytes()) |  | ||||||
| 	ext.GasPrice = common.ToHex(t.GasPrice.Bytes()) |  | ||||||
| 	ext.Input = common.ToHex(t.Input) |  | ||||||
|  |  | ||||||
| 	return json.Marshal(ext) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewTransactionRes(tx *types.Transaction) *TransactionRes { | func NewTransactionRes(tx *types.Transaction) *TransactionRes { | ||||||
| 	var v = new(TransactionRes) | 	var v = new(TransactionRes) | ||||||
| 	v.Hash = tx.Hash() | 	v.Hash = newHexData(tx.Hash()) | ||||||
| 	v.Nonce = tx.Nonce() | 	v.Nonce = newHexNum(tx.Nonce()) | ||||||
| 	v.From, _ = tx.From() | 	// v.BlockHash = | ||||||
| 	v.To = tx.To() | 	// v.BlockNumber = | ||||||
| 	v.Value = tx.Value() | 	// v.TxIndex = | ||||||
| 	v.Gas = tx.Gas() | 	from, _ := tx.From() | ||||||
| 	v.GasPrice = tx.GasPrice() | 	v.From = newHexData(from) | ||||||
| 	v.Input = tx.Data() | 	v.To = newHexData(tx.To()) | ||||||
|  | 	v.Value = newHexNum(tx.Value()) | ||||||
|  | 	v.Gas = newHexNum(tx.Gas()) | ||||||
|  | 	v.GasPrice = newHexNum(tx.GasPrice()) | ||||||
|  | 	v.Input = newHexData(tx.Data()) | ||||||
| 	return v | 	return v | ||||||
| } | } | ||||||
|  |  | ||||||
| type FilterLogRes struct { | func NewTransactionsRes(txs []*types.Transaction) []*TransactionRes { | ||||||
| 	Hash             string `json:"hash"` | 	v := make([]*TransactionRes, len(txs)) | ||||||
| 	Address          string `json:"address"` | 	for i, tx := range txs { | ||||||
| 	Data             string `json:"data"` | 		v[i] = NewTransactionRes(tx) | ||||||
| 	BlockNumber      string `json:"blockNumber"` | 	} | ||||||
| 	TransactionHash  string `json:"transactionHash"` | 	return v | ||||||
| 	BlockHash        string `json:"blockHash"` |  | ||||||
| 	TransactionIndex string `json:"transactionIndex"` |  | ||||||
| 	LogIndex         string `json:"logIndex"` |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type FilterWhisperRes struct { | // type FilterLogRes struct { | ||||||
| 	Hash       string `json:"hash"` | // 	Hash             string `json:"hash"` | ||||||
| 	From       string `json:"from"` | // 	Address          string `json:"address"` | ||||||
| 	To         string `json:"to"` | // 	Data             string `json:"data"` | ||||||
| 	Expiry     string `json:"expiry"` | // 	BlockNumber      string `json:"blockNumber"` | ||||||
| 	Sent       string `json:"sent"` | // 	TransactionHash  string `json:"transactionHash"` | ||||||
| 	Ttl        string `json:"ttl"` | // 	BlockHash        string `json:"blockHash"` | ||||||
| 	Topics     string `json:"topics"` | // 	TransactionIndex string `json:"transactionIndex"` | ||||||
| 	Payload    string `json:"payload"` | // 	LogIndex         string `json:"logIndex"` | ||||||
| 	WorkProved string `json:"workProved"` | // } | ||||||
| } |  | ||||||
|  | // 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"` | ||||||
|  | // } | ||||||
|  |  | ||||||
| type LogRes struct { | type LogRes struct { | ||||||
| 	Address common.Address `json:"address"` | 	Address          *hexdata   `json:"address"` | ||||||
| 	Topics  []common.Hash  `json:"topics"` | 	Topics           []*hexdata `json:"topics"` | ||||||
| 	Data    []byte         `json:"data"` | 	Data             *hexdata   `json:"data"` | ||||||
| 	Number  uint64         `json:"number"` | 	BlockNumber      *hexnum    `json:"blockNumber"` | ||||||
|  | 	Hash             *hexdata   `json:"hash"` | ||||||
|  | 	LogIndex         *hexnum    `json:"logIndex"` | ||||||
|  | 	BlockHash        *hexdata   `json:"blockHash"` | ||||||
|  | 	TransactionHash  *hexdata   `json:"transactionHash"` | ||||||
|  | 	TransactionIndex *hexnum    `json:"transactionIndex"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewLogRes(log state.Log) LogRes { | func NewLogRes(log state.Log) LogRes { | ||||||
| 	var l LogRes | 	var l LogRes | ||||||
| 	l.Topics = make([]common.Hash, len(log.Topics())) | 	l.Topics = make([]*hexdata, len(log.Topics())) | ||||||
| 	l.Address = log.Address() |  | ||||||
| 	l.Data = log.Data() |  | ||||||
| 	l.Number = log.Number() |  | ||||||
| 	for j, topic := range log.Topics() { | 	for j, topic := range log.Topics() { | ||||||
| 		l.Topics[j] = topic | 		l.Topics[j] = newHexData(topic) | ||||||
| 	} | 	} | ||||||
|  | 	l.Address = newHexData(log.Address()) | ||||||
|  | 	l.Data = newHexData(log.Data()) | ||||||
|  | 	l.BlockNumber = newHexNum(log.Number()) | ||||||
|  |  | ||||||
| 	return l | 	return l | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *LogRes) MarshalJSON() ([]byte, error) { |  | ||||||
| 	var ext struct { |  | ||||||
| 		Address string   `json:"address"` |  | ||||||
| 		Topics  []string `json:"topics"` |  | ||||||
| 		Data    string   `json:"data"` |  | ||||||
| 		Number  string   `json:"number"` |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ext.Address = l.Address.Hex() |  | ||||||
| 	ext.Data = common.ToHex(l.Data) |  | ||||||
| 	ext.Number = common.ToHex(big.NewInt(int64(l.Number)).Bytes()) |  | ||||||
| 	ext.Topics = make([]string, len(l.Topics)) |  | ||||||
| 	for i, v := range l.Topics { |  | ||||||
| 		ext.Topics[i] = v.Hex() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return json.Marshal(ext) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewLogsRes(logs state.Logs) (ls []LogRes) { | func NewLogsRes(logs state.Logs) (ls []LogRes) { | ||||||
| 	ls = make([]LogRes, len(logs)) | 	ls = make([]LogRes, len(logs)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ package rpc | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
| 	"math/big" | 	"math/big" | ||||||
|  | 	"regexp" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| @@ -10,6 +12,15 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/core/types" | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	reHash       = `"0x[0-9a-f]{64}"`               // 32 bytes | ||||||
|  | 	reHashOpt    = `"(0x[0-9a-f]{64})"|null`        // 32 bytes or null | ||||||
|  | 	reAddress    = `"0x[0-9a-f]{40}"`               // 20 bytes | ||||||
|  | 	reAddressOpt = `"0x[0-9a-f]{40}"|null`          // 20 bytes or null | ||||||
|  | 	reNum        = `"0x([1-9a-f][0-9a-f]{1,15})|0"` // must not have left-padded zeros | ||||||
|  | 	reData       = `"0x[0-9a-f]*"`                  // can be "empty" | ||||||
|  | ) | ||||||
|  |  | ||||||
| func TestNewBlockRes(t *testing.T) { | func TestNewBlockRes(t *testing.T) { | ||||||
| 	parentHash := common.HexToHash("0x01") | 	parentHash := common.HexToHash("0x01") | ||||||
| 	coinbase := common.HexToAddress("0x01") | 	coinbase := common.HexToAddress("0x01") | ||||||
| @@ -18,56 +29,35 @@ func TestNewBlockRes(t *testing.T) { | |||||||
| 	nonce := uint64(1) | 	nonce := uint64(1) | ||||||
| 	extra := "" | 	extra := "" | ||||||
| 	block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, extra) | 	block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, extra) | ||||||
|  | 	tests := map[string]string{ | ||||||
| 	_ = NewBlockRes(block) | 		"number":          reNum, | ||||||
| } | 		"hash":            reHash, | ||||||
|  | 		"parentHash":      reHash, | ||||||
| func TestBlockRes(t *testing.T) { | 		"nonce":           reNum, | ||||||
| 	v := &BlockRes{ | 		"sha3Uncles":      reHash, | ||||||
| 		BlockNumber:     big.NewInt(0), | 		"logsBloom":       reData, | ||||||
| 		BlockHash:       common.HexToHash("0x0"), | 		"transactionRoot": reHash, | ||||||
| 		ParentHash:      common.HexToHash("0x0"), | 		"stateRoot":       reHash, | ||||||
| 		Nonce:           [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, | 		"miner":           reAddress, | ||||||
| 		Sha3Uncles:      common.HexToHash("0x0"), | 		"difficulty":      `"0x1"`, | ||||||
| 		LogsBloom:       types.BytesToBloom([]byte{0}), | 		"totalDifficulty": reNum, | ||||||
| 		TransactionRoot: common.HexToHash("0x0"), | 		"size":            reNum, | ||||||
| 		StateRoot:       common.HexToHash("0x0"), | 		"extraData":       reData, | ||||||
| 		Miner:           common.HexToAddress("0x0"), | 		"gasLimit":        reNum, | ||||||
| 		Difficulty:      big.NewInt(0), | 		// "minGasPrice":  "0x", | ||||||
| 		TotalDifficulty: big.NewInt(0), | 		"gasUsed":   reNum, | ||||||
| 		Size:            big.NewInt(0), | 		"timestamp": reNum, | ||||||
| 		ExtraData:       []byte{}, |  | ||||||
| 		GasLimit:        big.NewInt(0), |  | ||||||
| 		MinGasPrice:     int64(0), |  | ||||||
| 		GasUsed:         big.NewInt(0), |  | ||||||
| 		UnixTimestamp:   int64(0), |  | ||||||
| 		// Transactions    []*TransactionRes `json:"transactions"` |  | ||||||
| 		// Uncles          []common.Hash     `json:"uncles"` |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, _ = json.Marshal(v) | 	v := NewBlockRes(block) | ||||||
|  | 	j, _ := json.Marshal(v) | ||||||
|  |  | ||||||
| 	// fmt.Println(string(j)) | 	for k, re := range tests { | ||||||
|  | 		match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j)) | ||||||
| } | 		if !match { | ||||||
|  | 			t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j)) | ||||||
| func TestTransactionRes(t *testing.T) { | 		} | ||||||
| 	a := common.HexToAddress("0x0") |  | ||||||
| 	v := &TransactionRes{ |  | ||||||
| 		Hash:        common.HexToHash("0x0"), |  | ||||||
| 		Nonce:       uint64(0), |  | ||||||
| 		BlockHash:   common.HexToHash("0x0"), |  | ||||||
| 		BlockNumber: int64(0), |  | ||||||
| 		TxIndex:     int64(0), |  | ||||||
| 		From:        common.HexToAddress("0x0"), |  | ||||||
| 		To:          &a, |  | ||||||
| 		Value:       big.NewInt(0), |  | ||||||
| 		Gas:         big.NewInt(0), |  | ||||||
| 		GasPrice:    big.NewInt(0), |  | ||||||
| 		Input:       []byte{0}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, _ = json.Marshal(v) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestNewTransactionRes(t *testing.T) { | func TestNewTransactionRes(t *testing.T) { | ||||||
| @@ -78,26 +68,80 @@ func TestNewTransactionRes(t *testing.T) { | |||||||
| 	data := []byte{1, 2, 3} | 	data := []byte{1, 2, 3} | ||||||
| 	tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data) | 	tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data) | ||||||
|  |  | ||||||
| 	_ = NewTransactionRes(tx) | 	tests := map[string]string{ | ||||||
| } | 		"hash":             reHash, | ||||||
|  | 		"nonce":            reNum, | ||||||
| func TestLogRes(t *testing.T) { | 		"blockHash":        reHash, | ||||||
| 	topics := make([]common.Hash, 3) | 		"blockNum":         reNum, | ||||||
| 	topics = append(topics, common.HexToHash("0x00")) | 		"transactionIndex": reNum, | ||||||
| 	topics = append(topics, common.HexToHash("0x10")) | 		"from":             reAddress, | ||||||
| 	topics = append(topics, common.HexToHash("0x20")) | 		"to":               reAddressOpt, | ||||||
|  | 		"value":            reNum, | ||||||
| 	v := &LogRes{ | 		"gas":              reNum, | ||||||
| 		Topics:  topics, | 		"gasPrice":         reNum, | ||||||
| 		Address: common.HexToAddress("0x0"), | 		"input":            reData, | ||||||
| 		Data:    []byte{1, 2, 3}, | 	} | ||||||
| 		Number:  uint64(5), |  | ||||||
|  | 	v := NewTransactionRes(tx) | ||||||
|  | 	v.BlockHash = newHexData(common.HexToHash("0x030201")) | ||||||
|  | 	v.BlockNumber = newHexNum(5) | ||||||
|  | 	v.TxIndex = newHexNum(0) | ||||||
|  | 	j, _ := json.Marshal(v) | ||||||
|  | 	for k, re := range tests { | ||||||
|  | 		match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j)) | ||||||
|  | 		if !match { | ||||||
|  | 			t.Error(fmt.Sprintf("`%s` output json does not match format %s. Source %s", k, re, j)) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	_, _ = json.Marshal(v) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func MakeStateLog(num int) state.Log { | func TestNewLogRes(t *testing.T) { | ||||||
|  | 	log := makeStateLog(0) | ||||||
|  | 	tests := map[string]string{ | ||||||
|  | 		"address": reAddress, | ||||||
|  | 		// "topics": "[.*]" | ||||||
|  | 		"data":        reData, | ||||||
|  | 		"blockNumber": reNum, | ||||||
|  | 		// "hash":             reHash, | ||||||
|  | 		// "logIndex":         reNum, | ||||||
|  | 		// "blockHash":        reHash, | ||||||
|  | 		// "transactionHash":  reHash, | ||||||
|  | 		"transactionIndex": reNum, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	v := NewLogRes(log) | ||||||
|  | 	j, _ := json.Marshal(v) | ||||||
|  |  | ||||||
|  | 	for k, re := range tests { | ||||||
|  | 		match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j)) | ||||||
|  | 		if !match { | ||||||
|  | 			t.Error(fmt.Sprintf("`%s` output json does not match format %s. Got %s", k, re, j)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestNewLogsRes(t *testing.T) { | ||||||
|  | 	logs := make([]state.Log, 3) | ||||||
|  | 	logs[0] = makeStateLog(1) | ||||||
|  | 	logs[1] = makeStateLog(2) | ||||||
|  | 	logs[2] = makeStateLog(3) | ||||||
|  | 	tests := map[string]string{} | ||||||
|  |  | ||||||
|  | 	v := NewLogsRes(logs) | ||||||
|  | 	j, _ := json.Marshal(v) | ||||||
|  |  | ||||||
|  | 	for k, re := range tests { | ||||||
|  | 		match, _ := regexp.MatchString(fmt.Sprintf(`[{.*"%s":%s.*}]`, k, re), string(j)) | ||||||
|  | 		if !match { | ||||||
|  | 			t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func makeStateLog(num int) state.Log { | ||||||
| 	address := common.HexToAddress("0x0") | 	address := common.HexToAddress("0x0") | ||||||
| 	data := []byte{1, 2, 3} | 	data := []byte{1, 2, 3} | ||||||
| 	number := uint64(num) | 	number := uint64(num) | ||||||
| @@ -108,16 +152,3 @@ func MakeStateLog(num int) state.Log { | |||||||
| 	log := state.NewLog(address, topics, data, number) | 	log := state.NewLog(address, topics, data, number) | ||||||
| 	return log | 	return log | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestNewLogRes(t *testing.T) { |  | ||||||
| 	log := MakeStateLog(0) |  | ||||||
| 	_ = NewLogRes(log) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestNewLogsRes(t *testing.T) { |  | ||||||
| 	logs := make([]state.Log, 3) |  | ||||||
| 	logs[0] = MakeStateLog(1) |  | ||||||
| 	logs[1] = MakeStateLog(2) |  | ||||||
| 	logs[2] = MakeStateLog(3) |  | ||||||
| 	_ = NewLogsRes(logs) |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								xeth/xeth.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								xeth/xeth.go
									
									
									
									
									
								
							| @@ -19,6 +19,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/event/filter" | 	"github.com/ethereum/go-ethereum/event/filter" | ||||||
| 	"github.com/ethereum/go-ethereum/logger" | 	"github.com/ethereum/go-ethereum/logger" | ||||||
| 	"github.com/ethereum/go-ethereum/miner" | 	"github.com/ethereum/go-ethereum/miner" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| @@ -185,12 +186,29 @@ func (self *XEth) EthBlockByHash(strHash string) *types.Block { | |||||||
| 	return block | 	return block | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *XEth) EthTransactionByHash(hash string) *types.Transaction { | func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) { | ||||||
| 	data, _ := self.backend.ExtraDb().Get(common.FromHex(hash)) | 	data, _ := self.backend.ExtraDb().Get(common.FromHex(hash)) | ||||||
| 	if len(data) != 0 { | 	if len(data) != 0 { | ||||||
| 		return types.NewTransactionFromBytes(data) | 		tx = types.NewTransactionFromBytes(data) | ||||||
| 	} | 	} | ||||||
| 	return nil |  | ||||||
|  | 	// meta | ||||||
|  | 	var txExtra struct { | ||||||
|  | 		BlockHash  common.Hash | ||||||
|  | 		BlockIndex int64 | ||||||
|  | 		Index      uint64 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	v, _ := self.backend.ExtraDb().Get(append(common.FromHex(hash), 0x0001)) | ||||||
|  | 	r := bytes.NewReader(v) | ||||||
|  | 	err := rlp.Decode(r, &txExtra) | ||||||
|  | 	if err == nil { | ||||||
|  | 		blhash = txExtra.BlockHash | ||||||
|  | 		blnum = big.NewInt(txExtra.BlockIndex) | ||||||
|  | 		txi = txExtra.Index | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *XEth) BlockByNumber(num int64) *Block { | func (self *XEth) BlockByNumber(num int64) *Block { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user