2015-03-25 15:50:30 +00:00
|
|
|
package rpc
|
|
|
|
|
|
|
|
import (
|
2015-04-01 09:38:06 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2015-04-01 07:11:23 +00:00
|
|
|
"math/big"
|
2015-04-01 09:38:06 +00:00
|
|
|
"regexp"
|
2015-04-01 07:11:23 +00:00
|
|
|
"testing"
|
2015-03-25 15:50:30 +00:00
|
|
|
|
2015-04-01 07:11:23 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
2015-03-25 15:50:30 +00:00
|
|
|
)
|
|
|
|
|
2015-04-01 09:38:06 +00:00
|
|
|
const (
|
2015-04-01 13:27:14 +00:00
|
|
|
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]{0,15})|0"` // must not have left-padded zeros
|
2015-04-01 13:44:09 +00:00
|
|
|
reNumNonZero = `"0x([1-9a-f][0-9a-f]{0,15})"` // non-zero required must not have left-padded zeros
|
2015-04-01 13:27:14 +00:00
|
|
|
reNumOpt = `"0x([1-9a-f][0-9a-f]{0,15})|0"|null` // must not have left-padded zeros or null
|
|
|
|
reData = `"0x[0-9a-f]*"` // can be "empty"
|
2015-04-01 14:49:07 +00:00
|
|
|
// reListHash = `[("\w":"0x[0-9a-f]{64}",?)*]`
|
|
|
|
// reListObj = `[("\w":(".+"|null),?)*]`
|
2015-04-01 09:38:06 +00:00
|
|
|
)
|
|
|
|
|
2015-04-01 07:11:23 +00:00
|
|
|
func TestNewBlockRes(t *testing.T) {
|
2015-04-01 09:38:06 +00:00
|
|
|
tests := map[string]string{
|
2015-04-02 10:30:22 +00:00
|
|
|
"number": reNum,
|
|
|
|
"hash": reHash,
|
|
|
|
"parentHash": reHash,
|
|
|
|
"nonce": reData,
|
|
|
|
"sha3Uncles": reHash,
|
|
|
|
"logsBloom": reData,
|
|
|
|
"transactionsRoot": reHash,
|
|
|
|
"stateRoot": reHash,
|
|
|
|
"miner": reAddress,
|
|
|
|
"difficulty": `"0x1"`,
|
|
|
|
"totalDifficulty": reNum,
|
|
|
|
"size": reNumNonZero,
|
|
|
|
"extraData": reData,
|
|
|
|
"gasLimit": reNum,
|
2015-04-01 09:38:06 +00:00
|
|
|
// "minGasPrice": "0x",
|
|
|
|
"gasUsed": reNum,
|
|
|
|
"timestamp": reNum,
|
2015-04-01 14:49:07 +00:00
|
|
|
// "transactions": reListHash,
|
|
|
|
// "uncles": reListHash,
|
2015-04-01 09:38:06 +00:00
|
|
|
}
|
2015-04-01 07:11:23 +00:00
|
|
|
|
2015-04-04 12:08:35 +00:00
|
|
|
block := makeBlock()
|
2015-04-01 11:18:30 +00:00
|
|
|
v := NewBlockRes(block, false)
|
2015-04-01 14:49:07 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-04 12:08:35 +00:00
|
|
|
func TestNewBlockResTxFull(t *testing.T) {
|
2015-04-01 14:49:07 +00:00
|
|
|
tests := map[string]string{
|
2015-04-02 10:30:22 +00:00
|
|
|
"number": reNum,
|
|
|
|
"hash": reHash,
|
|
|
|
"parentHash": reHash,
|
|
|
|
"nonce": reData,
|
|
|
|
"sha3Uncles": reHash,
|
|
|
|
"logsBloom": reData,
|
|
|
|
"transactionsRoot": reHash,
|
|
|
|
"stateRoot": reHash,
|
|
|
|
"miner": reAddress,
|
|
|
|
"difficulty": `"0x1"`,
|
|
|
|
"totalDifficulty": reNum,
|
|
|
|
"size": reNumNonZero,
|
|
|
|
"extraData": reData,
|
|
|
|
"gasLimit": reNum,
|
2015-04-01 14:49:07 +00:00
|
|
|
// "minGasPrice": "0x",
|
|
|
|
"gasUsed": reNum,
|
|
|
|
"timestamp": reNum,
|
2015-04-04 12:08:35 +00:00
|
|
|
// "transactions": reListHash,
|
2015-04-01 14:49:07 +00:00
|
|
|
// "uncles": reListHash,
|
|
|
|
}
|
|
|
|
|
2015-04-04 12:08:35 +00:00
|
|
|
block := makeBlock()
|
2015-04-01 14:49:07 +00:00
|
|
|
v := NewBlockRes(block, true)
|
2015-04-01 09:38:06 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
2015-04-01 07:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-04-04 12:08:35 +00:00
|
|
|
func TestBlockNil(t *testing.T) {
|
|
|
|
var block *types.Block
|
|
|
|
block = nil
|
|
|
|
u := NewBlockRes(block, false)
|
|
|
|
j, _ := json.Marshal(u)
|
|
|
|
if string(j) != "null" {
|
|
|
|
t.Errorf("Expected null but got %v", string(j))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-01 07:11:23 +00:00
|
|
|
func TestNewTransactionRes(t *testing.T) {
|
|
|
|
to := common.HexToAddress("0x02")
|
|
|
|
amount := big.NewInt(1)
|
|
|
|
gasAmount := big.NewInt(1)
|
|
|
|
gasPrice := big.NewInt(1)
|
|
|
|
data := []byte{1, 2, 3}
|
|
|
|
tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data)
|
|
|
|
|
2015-04-01 09:38:06 +00:00
|
|
|
tests := map[string]string{
|
|
|
|
"hash": reHash,
|
|
|
|
"nonce": reNum,
|
2015-04-01 13:27:37 +00:00
|
|
|
"blockHash": reHashOpt,
|
|
|
|
"blockNum": reNumOpt,
|
|
|
|
"transactionIndex": reNumOpt,
|
2015-04-01 09:38:06 +00:00
|
|
|
"from": reAddress,
|
|
|
|
"to": reAddressOpt,
|
|
|
|
"value": reNum,
|
|
|
|
"gas": reNum,
|
|
|
|
"gasPrice": reNum,
|
|
|
|
"input": reData,
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-01 07:11:23 +00:00
|
|
|
}
|
|
|
|
|
2015-04-04 12:08:35 +00:00
|
|
|
func TestTransactionNil(t *testing.T) {
|
|
|
|
var tx *types.Transaction
|
|
|
|
tx = nil
|
|
|
|
u := NewTransactionRes(tx)
|
|
|
|
j, _ := json.Marshal(u)
|
|
|
|
if string(j) != "null" {
|
|
|
|
t.Errorf("Expected null but got %v", string(j))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewUncleRes(t *testing.T) {
|
|
|
|
header := makeHeader()
|
|
|
|
u := NewUncleRes(header)
|
|
|
|
tests := map[string]string{
|
|
|
|
"number": reNum,
|
|
|
|
"hash": reHash,
|
|
|
|
"parentHash": reHash,
|
|
|
|
"nonce": reData,
|
|
|
|
"sha3Uncles": reHash,
|
|
|
|
"receiptHash": reHash,
|
|
|
|
"transactionsRoot": reHash,
|
|
|
|
"stateRoot": reHash,
|
|
|
|
"miner": reAddress,
|
|
|
|
"difficulty": reNum,
|
|
|
|
"extraData": reData,
|
|
|
|
"gasLimit": reNum,
|
|
|
|
"gasUsed": reNum,
|
|
|
|
"timestamp": reNum,
|
|
|
|
}
|
|
|
|
|
|
|
|
j, _ := json.Marshal(u)
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUncleNil(t *testing.T) {
|
|
|
|
var header *types.Header
|
|
|
|
header = nil
|
|
|
|
u := NewUncleRes(header)
|
|
|
|
j, _ := json.Marshal(u)
|
|
|
|
if string(j) != "null" {
|
|
|
|
t.Errorf("Expected null but got %v", string(j))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-01 09:38:06 +00:00
|
|
|
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 {
|
2015-04-01 07:11:23 +00:00
|
|
|
address := common.HexToAddress("0x0")
|
|
|
|
data := []byte{1, 2, 3}
|
|
|
|
number := uint64(num)
|
|
|
|
topics := make([]common.Hash, 3)
|
|
|
|
topics = append(topics, common.HexToHash("0x00"))
|
|
|
|
topics = append(topics, common.HexToHash("0x10"))
|
|
|
|
topics = append(topics, common.HexToHash("0x20"))
|
|
|
|
log := state.NewLog(address, topics, data, number)
|
|
|
|
return log
|
|
|
|
}
|
2015-04-04 12:08:35 +00:00
|
|
|
|
|
|
|
func makeHeader() *types.Header {
|
|
|
|
header := &types.Header{
|
|
|
|
ParentHash: common.StringToHash("0x00"),
|
|
|
|
UncleHash: common.StringToHash("0x00"),
|
|
|
|
Coinbase: common.StringToAddress("0x00"),
|
|
|
|
Root: common.StringToHash("0x00"),
|
|
|
|
TxHash: common.StringToHash("0x00"),
|
|
|
|
ReceiptHash: common.StringToHash("0x00"),
|
|
|
|
// Bloom:
|
|
|
|
Difficulty: big.NewInt(88888888),
|
|
|
|
Number: big.NewInt(16),
|
|
|
|
GasLimit: big.NewInt(70000),
|
|
|
|
GasUsed: big.NewInt(25000),
|
|
|
|
Time: 124356789,
|
2015-04-07 13:04:29 +00:00
|
|
|
Extra: nil,
|
2015-04-04 12:08:35 +00:00
|
|
|
MixDigest: common.StringToHash("0x00"),
|
|
|
|
Nonce: [8]byte{0, 1, 2, 3, 4, 5, 6, 7},
|
|
|
|
}
|
|
|
|
return header
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeBlock() *types.Block {
|
|
|
|
parentHash := common.HexToHash("0x01")
|
|
|
|
coinbase := common.HexToAddress("0x01")
|
|
|
|
root := common.HexToHash("0x01")
|
|
|
|
difficulty := common.Big1
|
|
|
|
nonce := uint64(1)
|
2015-04-07 13:04:29 +00:00
|
|
|
block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, nil)
|
2015-04-04 12:08:35 +00:00
|
|
|
|
|
|
|
txto := common.HexToAddress("0x02")
|
|
|
|
txamount := big.NewInt(1)
|
|
|
|
txgasAmount := big.NewInt(1)
|
|
|
|
txgasPrice := big.NewInt(1)
|
|
|
|
txdata := []byte{1, 2, 3}
|
|
|
|
|
|
|
|
tx := types.NewTransactionMessage(txto, txamount, txgasAmount, txgasPrice, txdata)
|
|
|
|
txs := make([]*types.Transaction, 1)
|
|
|
|
txs[0] = tx
|
|
|
|
block.SetTransactions(txs)
|
|
|
|
|
|
|
|
uncles := make([]*types.Header, 1)
|
|
|
|
uncles[0] = makeHeader()
|
|
|
|
block.SetUncles(uncles)
|
|
|
|
|
|
|
|
return block
|
|
|
|
}
|