forked from cerc-io/plugeth
Merge pull request #2064 from fjl/remove-common-rlp
common: remove old RLP implementation, Value and ExtPackage
This commit is contained in:
commit
dbbcf558e2
@ -137,8 +137,7 @@ func upgradeDB(ctx *cli.Context) {
|
||||
glog.Infoln("Upgrading blockchain database")
|
||||
|
||||
chain, chainDb := utils.MakeChain(ctx)
|
||||
v, _ := chainDb.Get([]byte("BlockchainVersion"))
|
||||
bcVersion := int(common.NewValue(v).Uint())
|
||||
bcVersion := core.GetBlockChainVersion(chainDb)
|
||||
if bcVersion == 0 {
|
||||
bcVersion = core.BlockChainVersion
|
||||
}
|
||||
@ -154,7 +153,7 @@ func upgradeDB(ctx *cli.Context) {
|
||||
|
||||
// Import the chain file.
|
||||
chain, chainDb = utils.MakeChain(ctx)
|
||||
chainDb.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
|
||||
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
|
||||
err := utils.ImportChain(chain, exportFile)
|
||||
chainDb.Close()
|
||||
if err != nil {
|
||||
|
@ -1,139 +0,0 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Manifest object
|
||||
//
|
||||
// The manifest object holds all the relevant information supplied with the
|
||||
// the manifest specified in the package
|
||||
type Manifest struct {
|
||||
Entry string
|
||||
Height, Width int
|
||||
}
|
||||
|
||||
// External package
|
||||
//
|
||||
// External package contains the main html file and manifest
|
||||
type ExtPackage struct {
|
||||
EntryHtml string
|
||||
Manifest *Manifest
|
||||
}
|
||||
|
||||
// Read file
|
||||
//
|
||||
// Read a given compressed file and returns the read bytes.
|
||||
// Returns an error otherwise
|
||||
func ReadFile(f *zip.File) ([]byte, error) {
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// Reads manifest
|
||||
//
|
||||
// Reads and returns a manifest object. Returns error otherwise
|
||||
func ReadManifest(m []byte) (*Manifest, error) {
|
||||
var manifest Manifest
|
||||
|
||||
dec := json.NewDecoder(strings.NewReader(string(m)))
|
||||
if err := dec.Decode(&manifest); err == io.EOF {
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &manifest, nil
|
||||
}
|
||||
|
||||
// Find file in archive
|
||||
//
|
||||
// Returns the index of the given file name if it exists. -1 if file not found
|
||||
func FindFileInArchive(fn string, files []*zip.File) (index int) {
|
||||
index = -1
|
||||
// Find the manifest first
|
||||
for i, f := range files {
|
||||
if f.Name == fn {
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Open package
|
||||
//
|
||||
// Opens a prepared ethereum package
|
||||
// Reads the manifest file and determines file contents and returns and
|
||||
// the external package.
|
||||
func OpenPackage(fn string) (*ExtPackage, error) {
|
||||
r, err := zip.OpenReader(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
manifestIndex := FindFileInArchive("manifest.json", r.File)
|
||||
|
||||
if manifestIndex < 0 {
|
||||
return nil, fmt.Errorf("No manifest file found in archive")
|
||||
}
|
||||
|
||||
f, err := ReadFile(r.File[manifestIndex])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
manifest, err := ReadManifest(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if manifest.Entry == "" {
|
||||
return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry)
|
||||
}
|
||||
|
||||
entryIndex := FindFileInArchive(manifest.Entry, r.File)
|
||||
if entryIndex < 0 {
|
||||
return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry)
|
||||
}
|
||||
|
||||
f, err = ReadFile(r.File[entryIndex])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extPackage := &ExtPackage{string(f), manifest}
|
||||
|
||||
return extPackage, nil
|
||||
}
|
292
common/rlp.go
292
common/rlp.go
@ -1,292 +0,0 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type RlpEncode interface {
|
||||
RlpEncode() []byte
|
||||
}
|
||||
|
||||
type RlpEncodeDecode interface {
|
||||
RlpEncode
|
||||
RlpValue() []interface{}
|
||||
}
|
||||
|
||||
type RlpEncodable interface {
|
||||
RlpData() interface{}
|
||||
}
|
||||
|
||||
func Rlp(encoder RlpEncode) []byte {
|
||||
return encoder.RlpEncode()
|
||||
}
|
||||
|
||||
type RlpEncoder struct {
|
||||
rlpData []byte
|
||||
}
|
||||
|
||||
func NewRlpEncoder() *RlpEncoder {
|
||||
encoder := &RlpEncoder{}
|
||||
|
||||
return encoder
|
||||
}
|
||||
func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte {
|
||||
return Encode(rlpData)
|
||||
}
|
||||
|
||||
const (
|
||||
RlpEmptyList = 0x80
|
||||
RlpEmptyStr = 0x40
|
||||
)
|
||||
|
||||
const rlpEof = -1
|
||||
|
||||
func Char(c []byte) int {
|
||||
if len(c) > 0 {
|
||||
return int(c[0])
|
||||
}
|
||||
|
||||
return rlpEof
|
||||
}
|
||||
|
||||
func DecodeWithReader(reader *bytes.Buffer) interface{} {
|
||||
var slice []interface{}
|
||||
|
||||
// Read the next byte
|
||||
char := Char(reader.Next(1))
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return char
|
||||
|
||||
case char <= 0xb7:
|
||||
return reader.Next(int(char - 0x80))
|
||||
|
||||
case char <= 0xbf:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xb7)))
|
||||
|
||||
return reader.Next(int(length))
|
||||
|
||||
case char <= 0xf7:
|
||||
length := int(char - 0xc0)
|
||||
for i := 0; i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
case char <= 0xff:
|
||||
length := ReadVarInt(reader.Next(int(char - 0xf7)))
|
||||
for i := uint64(0); i < length; i++ {
|
||||
obj := DecodeWithReader(reader)
|
||||
slice = append(slice, obj)
|
||||
}
|
||||
|
||||
return slice
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
var (
|
||||
directRlp = big.NewInt(0x7f)
|
||||
numberRlp = big.NewInt(0xb7)
|
||||
zeroRlp = big.NewInt(0x0)
|
||||
)
|
||||
|
||||
func intlen(i int64) (length int) {
|
||||
for i > 0 {
|
||||
i = i >> 8
|
||||
length++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Encode(object interface{}) []byte {
|
||||
var buff bytes.Buffer
|
||||
|
||||
if object != nil {
|
||||
switch t := object.(type) {
|
||||
case *Value:
|
||||
buff.Write(Encode(t.Val))
|
||||
case RlpEncodable:
|
||||
buff.Write(Encode(t.RlpData()))
|
||||
// Code dup :-/
|
||||
case int:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int8:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case int64:
|
||||
buff.Write(Encode(big.NewInt(t)))
|
||||
case uint16:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint32:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case uint64:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case byte:
|
||||
buff.Write(Encode(big.NewInt(int64(t))))
|
||||
case *big.Int:
|
||||
// Not sure how this is possible while we check for nil
|
||||
if t == nil {
|
||||
buff.WriteByte(0xc0)
|
||||
} else {
|
||||
buff.Write(Encode(t.Bytes()))
|
||||
}
|
||||
case Bytes:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []byte:
|
||||
if len(t) == 1 && t[0] <= 0x7f {
|
||||
buff.Write(t)
|
||||
} else if len(t) < 56 {
|
||||
buff.WriteByte(byte(len(t) + 0x80))
|
||||
buff.Write(t)
|
||||
} else {
|
||||
b := big.NewInt(int64(len(t)))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xb7))
|
||||
buff.Write(b.Bytes())
|
||||
buff.Write(t)
|
||||
}
|
||||
case string:
|
||||
buff.Write(Encode([]byte(t)))
|
||||
case []interface{}:
|
||||
// Inline function for writing the slice header
|
||||
WriteSliceHeader := func(length int) {
|
||||
if length < 56 {
|
||||
buff.WriteByte(byte(length + 0xc0))
|
||||
} else {
|
||||
b := big.NewInt(int64(length))
|
||||
buff.WriteByte(byte(len(b.Bytes()) + 0xf7))
|
||||
buff.Write(b.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
for _, val := range t {
|
||||
b.Write(Encode(val))
|
||||
}
|
||||
WriteSliceHeader(len(b.Bytes()))
|
||||
buff.Write(b.Bytes())
|
||||
default:
|
||||
// This is how it should have been from the start
|
||||
// needs refactoring (@fjl)
|
||||
v := reflect.ValueOf(t)
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
var b bytes.Buffer
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
b.Write(Encode(v.Index(i).Interface()))
|
||||
}
|
||||
|
||||
blen := b.Len()
|
||||
if blen < 56 {
|
||||
buff.WriteByte(byte(blen) + 0xc0)
|
||||
} else {
|
||||
ilen := byte(intlen(int64(blen)))
|
||||
buff.WriteByte(ilen + 0xf7)
|
||||
t := make([]byte, ilen)
|
||||
for i := byte(0); i < ilen; i++ {
|
||||
t[ilen-i-1] = byte(blen >> (i * 8))
|
||||
}
|
||||
buff.Write(t)
|
||||
}
|
||||
buff.ReadFrom(&b)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Empty list for nil
|
||||
buff.WriteByte(0xc0)
|
||||
}
|
||||
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
// TODO Use a bytes.Buffer instead of a raw byte slice.
|
||||
// Cleaner code, and use draining instead of seeking the next bytes to read
|
||||
func Decode(data []byte, pos uint64) (interface{}, uint64) {
|
||||
var slice []interface{}
|
||||
char := int(data[pos])
|
||||
switch {
|
||||
case char <= 0x7f:
|
||||
return data[pos], pos + 1
|
||||
|
||||
case char <= 0xb7:
|
||||
b := uint64(data[pos]) - 0x80
|
||||
|
||||
return data[pos+1 : pos+1+b], pos + 1 + b
|
||||
|
||||
case char <= 0xbf:
|
||||
b := uint64(data[pos]) - 0xb7
|
||||
|
||||
b2 := ReadVarInt(data[pos+1 : pos+1+b])
|
||||
|
||||
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2
|
||||
|
||||
case char <= 0xf7:
|
||||
b := uint64(data[pos]) - 0xc0
|
||||
prevPos := pos
|
||||
pos++
|
||||
for i := uint64(0); i < b; {
|
||||
var obj interface{}
|
||||
|
||||
// Get the next item in the data list and append it
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
// Increment i by the amount bytes read in the previous
|
||||
// read
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
case char <= 0xff:
|
||||
l := uint64(data[pos]) - 0xf7
|
||||
b := ReadVarInt(data[pos+1 : pos+1+l])
|
||||
|
||||
pos = pos + l + 1
|
||||
|
||||
prevPos := b
|
||||
for i := uint64(0); i < uint64(b); {
|
||||
var obj interface{}
|
||||
|
||||
obj, prevPos = Decode(data, pos)
|
||||
slice = append(slice, obj)
|
||||
|
||||
i += (prevPos - pos)
|
||||
pos = prevPos
|
||||
}
|
||||
return slice, pos
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("byte not supported: %q", char))
|
||||
}
|
||||
|
||||
return slice, 0
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
func TestNonInterfaceSlice(t *testing.T) {
|
||||
vala := []string{"value1", "value2", "value3"}
|
||||
valb := []interface{}{"value1", "value2", "value3"}
|
||||
resa := Encode(vala)
|
||||
resb := Encode(valb)
|
||||
if !bytes.Equal(resa, resb) {
|
||||
t.Errorf("expected []string & []interface{} to be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRlpValueEncoding(t *testing.T) {
|
||||
val := EmptyValue()
|
||||
val.AppendList().Append(byte(1)).Append(byte(2)).Append(byte(3))
|
||||
val.Append("4").AppendList().Append(byte(5))
|
||||
|
||||
res, err := rlp.EncodeToBytes(val)
|
||||
if err != nil {
|
||||
t.Fatalf("encode error: %v", err)
|
||||
}
|
||||
exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}})
|
||||
if bytes.Compare(res, exp) != 0 {
|
||||
t.Errorf("expected %x, got %x", exp, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueSlice(t *testing.T) {
|
||||
val := []interface{}{
|
||||
"value1",
|
||||
"valeu2",
|
||||
"value3",
|
||||
}
|
||||
|
||||
value := NewValue(val)
|
||||
splitVal := value.SliceFrom(1)
|
||||
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
|
||||
splitVal = value.SliceTo(2)
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceTo: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
|
||||
splitVal = value.SliceFromTo(1, 3)
|
||||
if splitVal.Len() != 2 {
|
||||
t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLargeData(t *testing.T) {
|
||||
data := make([]byte, 100000)
|
||||
enc := Encode(data)
|
||||
value := NewValueFromBytes(enc)
|
||||
if value.Len() != len(data) {
|
||||
t.Error("Expected data to be", len(data), "got", value.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestValue(t *testing.T) {
|
||||
value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01"))
|
||||
if value.Get(0).Str() != "dog" {
|
||||
t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog")
|
||||
}
|
||||
|
||||
if value.Get(3).Uint() != 1 {
|
||||
t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
strRes := "\x83dog"
|
||||
bytes := Encode("dog")
|
||||
|
||||
str := string(bytes)
|
||||
if str != strRes {
|
||||
t.Errorf("Expected %q, got %q", strRes, str)
|
||||
}
|
||||
|
||||
sliceRes := "\xcc\x83dog\x83god\x83cat"
|
||||
strs := []interface{}{"dog", "god", "cat"}
|
||||
bytes = Encode(strs)
|
||||
slice := string(bytes)
|
||||
if slice != sliceRes {
|
||||
t.Error("Expected %q, got %q", sliceRes, slice)
|
||||
}
|
||||
|
||||
intRes := "\x82\x04\x00"
|
||||
bytes = Encode(1024)
|
||||
if string(bytes) != intRes {
|
||||
t.Errorf("Expected %q, got %q", intRes, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
single := []byte("\x01")
|
||||
b, _ := Decode(single, 0)
|
||||
|
||||
if b.(uint8) != 1 {
|
||||
t.Errorf("Expected 1, got %q", b)
|
||||
}
|
||||
|
||||
str := []byte("\x83dog")
|
||||
b, _ = Decode(str, 0)
|
||||
if bytes.Compare(b.([]byte), []byte("dog")) != 0 {
|
||||
t.Errorf("Expected dog, got %q", b)
|
||||
}
|
||||
|
||||
slice := []byte("\xcc\x83dog\x83god\x83cat")
|
||||
res := []interface{}{"dog", "god", "cat"}
|
||||
b, _ = Decode(slice, 0)
|
||||
if reflect.DeepEqual(b, res) {
|
||||
t.Errorf("Expected %q, got %q", res, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeBigInt(t *testing.T) {
|
||||
bigInt := big.NewInt(1391787038)
|
||||
encoded := Encode(bigInt)
|
||||
|
||||
value := NewValueFromBytes(encoded)
|
||||
if value.BigInt().Cmp(bigInt) != 0 {
|
||||
t.Errorf("Expected %v, got %v", bigInt, value.BigInt())
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeBytes(t *testing.T) {
|
||||
bv := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, []byte{6}})
|
||||
b, _ := rlp.EncodeToBytes(bv)
|
||||
val := NewValueFromBytes(b)
|
||||
if !bv.Cmp(val) {
|
||||
t.Errorf("Expected %#v, got %#v", bv, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeZero(t *testing.T) {
|
||||
b, _ := rlp.EncodeToBytes(NewValue(0))
|
||||
exp := []byte{0xc0}
|
||||
if bytes.Compare(b, exp) == 0 {
|
||||
t.Error("Expected", exp, "got", b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeDecode(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes := Encode([]interface{}{"dog", "god", "cat"})
|
||||
Decode(bytes, 0)
|
||||
}
|
||||
}
|
428
common/value.go
428
common/value.go
@ -1,428 +0,0 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// Value can hold values of certain basic types and provides ways to
|
||||
// convert between types without bothering to check whether the
|
||||
// conversion is actually meaningful.
|
||||
//
|
||||
// It currently supports the following types:
|
||||
//
|
||||
// - int{,8,16,32,64}
|
||||
// - uint{,8,16,32,64}
|
||||
// - *big.Int
|
||||
// - []byte, string
|
||||
// - []interface{}
|
||||
//
|
||||
// Value is useful whenever you feel that Go's types limit your
|
||||
// ability to express yourself. In these situations, use Value and
|
||||
// forget about this strong typing nonsense.
|
||||
type Value struct{ Val interface{} }
|
||||
|
||||
func (val *Value) String() string {
|
||||
return fmt.Sprintf("%x", val.Val)
|
||||
}
|
||||
|
||||
func NewValue(val interface{}) *Value {
|
||||
t := val
|
||||
if v, ok := val.(*Value); ok {
|
||||
t = v.Val
|
||||
}
|
||||
|
||||
return &Value{Val: t}
|
||||
}
|
||||
|
||||
func (val *Value) Type() reflect.Kind {
|
||||
return reflect.TypeOf(val.Val).Kind()
|
||||
}
|
||||
|
||||
func (val *Value) IsNil() bool {
|
||||
return val.Val == nil
|
||||
}
|
||||
|
||||
func (val *Value) Len() int {
|
||||
if data, ok := val.Val.([]interface{}); ok {
|
||||
return len(data)
|
||||
}
|
||||
|
||||
return len(val.Bytes())
|
||||
}
|
||||
|
||||
func (val *Value) Uint() uint64 {
|
||||
if Val, ok := val.Val.(uint8); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint16); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint32); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint64); ok {
|
||||
return Val
|
||||
} else if Val, ok := val.Val.(float32); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(float64); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(int); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.(uint); ok {
|
||||
return uint64(Val)
|
||||
} else if Val, ok := val.Val.([]byte); ok {
|
||||
return new(big.Int).SetBytes(Val).Uint64()
|
||||
} else if Val, ok := val.Val.(*big.Int); ok {
|
||||
return Val.Uint64()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (val *Value) Int() int64 {
|
||||
if Val, ok := val.Val.(int8); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int16); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int32); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(int64); ok {
|
||||
return Val
|
||||
} else if Val, ok := val.Val.(int); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(float32); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.(float64); ok {
|
||||
return int64(Val)
|
||||
} else if Val, ok := val.Val.([]byte); ok {
|
||||
return new(big.Int).SetBytes(Val).Int64()
|
||||
} else if Val, ok := val.Val.(*big.Int); ok {
|
||||
return Val.Int64()
|
||||
} else if Val, ok := val.Val.(string); ok {
|
||||
n, _ := strconv.Atoi(Val)
|
||||
return int64(n)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (val *Value) Byte() byte {
|
||||
if Val, ok := val.Val.(byte); ok {
|
||||
return Val
|
||||
}
|
||||
|
||||
return 0x0
|
||||
}
|
||||
|
||||
func (val *Value) BigInt() *big.Int {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
b := new(big.Int).SetBytes(a)
|
||||
|
||||
return b
|
||||
} else if a, ok := val.Val.(*big.Int); ok {
|
||||
return a
|
||||
} else if a, ok := val.Val.(string); ok {
|
||||
return Big(a)
|
||||
} else {
|
||||
return big.NewInt(int64(val.Uint()))
|
||||
}
|
||||
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
func (val *Value) Str() string {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
return string(a)
|
||||
} else if a, ok := val.Val.(string); ok {
|
||||
return a
|
||||
} else if a, ok := val.Val.(byte); ok {
|
||||
return string(a)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (val *Value) Bytes() []byte {
|
||||
if a, ok := val.Val.([]byte); ok {
|
||||
return a
|
||||
} else if s, ok := val.Val.(byte); ok {
|
||||
return []byte{s}
|
||||
} else if s, ok := val.Val.(string); ok {
|
||||
return []byte(s)
|
||||
} else if s, ok := val.Val.(*big.Int); ok {
|
||||
return s.Bytes()
|
||||
} else {
|
||||
return big.NewInt(val.Int()).Bytes()
|
||||
}
|
||||
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (val *Value) Err() error {
|
||||
if err, ok := val.Val.(error); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (val *Value) Slice() []interface{} {
|
||||
if d, ok := val.Val.([]interface{}); ok {
|
||||
return d
|
||||
}
|
||||
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
func (val *Value) SliceFrom(from int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[from:])
|
||||
}
|
||||
|
||||
func (val *Value) SliceTo(to int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[:to])
|
||||
}
|
||||
|
||||
func (val *Value) SliceFromTo(from, to int) *Value {
|
||||
slice := val.Slice()
|
||||
|
||||
return NewValue(slice[from:to])
|
||||
}
|
||||
|
||||
// TODO More type checking methods
|
||||
func (val *Value) IsSlice() bool {
|
||||
return val.Type() == reflect.Slice
|
||||
}
|
||||
|
||||
func (val *Value) IsStr() bool {
|
||||
return val.Type() == reflect.String
|
||||
}
|
||||
|
||||
func (self *Value) IsErr() bool {
|
||||
_, ok := self.Val.(error)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Special list checking function. Something is considered
|
||||
// a list if it's of type []interface{}. The list is usually
|
||||
// used in conjunction with rlp decoded streams.
|
||||
func (val *Value) IsList() bool {
|
||||
_, ok := val.Val.([]interface{})
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (val *Value) IsEmpty() bool {
|
||||
return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0)
|
||||
}
|
||||
|
||||
// Threat the value as a slice
|
||||
func (val *Value) Get(idx int) *Value {
|
||||
if d, ok := val.Val.([]interface{}); ok {
|
||||
// Guard for oob
|
||||
if len(d) <= idx {
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
if idx < 0 {
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
return NewValue(d[idx])
|
||||
}
|
||||
|
||||
// If this wasn't a slice you probably shouldn't be using this function
|
||||
return NewValue(nil)
|
||||
}
|
||||
|
||||
func (self *Value) Copy() *Value {
|
||||
switch val := self.Val.(type) {
|
||||
case *big.Int:
|
||||
return NewValue(new(big.Int).Set(val))
|
||||
case []byte:
|
||||
return NewValue(CopyBytes(val))
|
||||
default:
|
||||
return NewValue(self.Val)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (val *Value) Cmp(o *Value) bool {
|
||||
return reflect.DeepEqual(val.Val, o.Val)
|
||||
}
|
||||
|
||||
func (self *Value) DeepCmp(o *Value) bool {
|
||||
return bytes.Compare(self.Bytes(), o.Bytes()) == 0
|
||||
}
|
||||
|
||||
func (self *Value) DecodeRLP(s *rlp.Stream) error {
|
||||
var v interface{}
|
||||
if err := s.Decode(&v); err != nil {
|
||||
return err
|
||||
}
|
||||
self.Val = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Value) EncodeRLP(w io.Writer) error {
|
||||
if self == nil {
|
||||
w.Write(rlp.EmptyList)
|
||||
return nil
|
||||
} else {
|
||||
return rlp.Encode(w, self.Val)
|
||||
}
|
||||
}
|
||||
|
||||
// NewValueFromBytes decodes RLP data.
|
||||
// The contained value will be nil if data contains invalid RLP.
|
||||
func NewValueFromBytes(data []byte) *Value {
|
||||
v := new(Value)
|
||||
if len(data) != 0 {
|
||||
if err := rlp.DecodeBytes(data, v); err != nil {
|
||||
v.Val = nil
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Value setters
|
||||
func NewSliceValue(s interface{}) *Value {
|
||||
list := EmptyValue()
|
||||
|
||||
if s != nil {
|
||||
if slice, ok := s.([]interface{}); ok {
|
||||
for _, val := range slice {
|
||||
list.Append(val)
|
||||
}
|
||||
} else if slice, ok := s.([]string); ok {
|
||||
for _, val := range slice {
|
||||
list.Append(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func EmptyValue() *Value {
|
||||
return NewValue([]interface{}{})
|
||||
}
|
||||
|
||||
func (val *Value) AppendList() *Value {
|
||||
list := EmptyValue()
|
||||
val.Val = append(val.Slice(), list)
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (val *Value) Append(v interface{}) *Value {
|
||||
val.Val = append(val.Slice(), v)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
const (
|
||||
valOpAdd = iota
|
||||
valOpDiv
|
||||
valOpMul
|
||||
valOpPow
|
||||
valOpSub
|
||||
)
|
||||
|
||||
// Math stuff
|
||||
func (self *Value) doOp(op int, other interface{}) *Value {
|
||||
left := self.BigInt()
|
||||
right := NewValue(other).BigInt()
|
||||
|
||||
switch op {
|
||||
case valOpAdd:
|
||||
self.Val = left.Add(left, right)
|
||||
case valOpDiv:
|
||||
self.Val = left.Div(left, right)
|
||||
case valOpMul:
|
||||
self.Val = left.Mul(left, right)
|
||||
case valOpPow:
|
||||
self.Val = left.Exp(left, right, Big0)
|
||||
case valOpSub:
|
||||
self.Val = left.Sub(left, right)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Value) Add(other interface{}) *Value {
|
||||
return self.doOp(valOpAdd, other)
|
||||
}
|
||||
|
||||
func (self *Value) Sub(other interface{}) *Value {
|
||||
return self.doOp(valOpSub, other)
|
||||
}
|
||||
|
||||
func (self *Value) Div(other interface{}) *Value {
|
||||
return self.doOp(valOpDiv, other)
|
||||
}
|
||||
|
||||
func (self *Value) Mul(other interface{}) *Value {
|
||||
return self.doOp(valOpMul, other)
|
||||
}
|
||||
|
||||
func (self *Value) Pow(other interface{}) *Value {
|
||||
return self.doOp(valOpPow, other)
|
||||
}
|
||||
|
||||
type ValueIterator struct {
|
||||
value *Value
|
||||
currentValue *Value
|
||||
idx int
|
||||
}
|
||||
|
||||
func (val *Value) NewIterator() *ValueIterator {
|
||||
return &ValueIterator{value: val}
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Len() int {
|
||||
return it.value.Len()
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Next() bool {
|
||||
if it.idx >= it.value.Len() {
|
||||
return false
|
||||
}
|
||||
|
||||
it.currentValue = it.value.Get(it.idx)
|
||||
it.idx++
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Value() *Value {
|
||||
return it.currentValue
|
||||
}
|
||||
|
||||
func (it *ValueIterator) Idx() int {
|
||||
return it.idx - 1
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
checker "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type ValueSuite struct{}
|
||||
|
||||
var _ = checker.Suite(&ValueSuite{})
|
||||
|
||||
func (s *ValueSuite) TestValueCmp(c *checker.C) {
|
||||
val1 := NewValue("hello")
|
||||
val2 := NewValue("world")
|
||||
c.Assert(val1.Cmp(val2), checker.Equals, false)
|
||||
|
||||
val3 := NewValue("hello")
|
||||
val4 := NewValue("hello")
|
||||
c.Assert(val3.Cmp(val4), checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *ValueSuite) TestValueTypes(c *checker.C) {
|
||||
str := NewValue("str")
|
||||
num := NewValue(1)
|
||||
inter := NewValue([]interface{}{1})
|
||||
byt := NewValue([]byte{1, 2, 3, 4})
|
||||
bigInt := NewValue(big.NewInt(10))
|
||||
|
||||
strExp := "str"
|
||||
numExp := uint64(1)
|
||||
interExp := []interface{}{1}
|
||||
bytExp := []byte{1, 2, 3, 4}
|
||||
bigExp := big.NewInt(10)
|
||||
|
||||
c.Assert(str.Str(), checker.Equals, strExp)
|
||||
c.Assert(num.Uint(), checker.Equals, numExp)
|
||||
c.Assert(NewValue(inter.Val).Cmp(NewValue(interExp)), checker.Equals, true)
|
||||
c.Assert(byt.Bytes(), checker.DeepEquals, bytExp)
|
||||
c.Assert(bigInt.BigInt(), checker.DeepEquals, bigExp)
|
||||
}
|
||||
|
||||
func (s *ValueSuite) TestIterator(c *checker.C) {
|
||||
value := NewValue([]interface{}{1, 2, 3})
|
||||
iter := value.NewIterator()
|
||||
values := []uint64{1, 2, 3}
|
||||
i := 0
|
||||
for iter.Next() {
|
||||
c.Assert(values[i], checker.Equals, iter.Value().Uint())
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ValueSuite) TestMath(c *checker.C) {
|
||||
data1 := NewValue(1)
|
||||
data1.Add(1).Add(1)
|
||||
exp1 := NewValue(3)
|
||||
data2 := NewValue(2)
|
||||
data2.Sub(1).Sub(1)
|
||||
exp2 := NewValue(0)
|
||||
|
||||
c.Assert(data1.DeepCmp(exp1), checker.Equals, true)
|
||||
c.Assert(data2.DeepCmp(exp2), checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *ValueSuite) TestString(c *checker.C) {
|
||||
data := "10"
|
||||
exp := int64(10)
|
||||
c.Assert(NewValue(data).Int(), checker.DeepEquals, exp)
|
||||
}
|
@ -104,6 +104,11 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||
b.receipts = append(b.receipts, receipt)
|
||||
}
|
||||
|
||||
// Number returns the block number of the block being generated.
|
||||
func (b *BlockGen) Number() *big.Int {
|
||||
return new(big.Int).Set(b.header.Number)
|
||||
}
|
||||
|
||||
// AddUncheckedReceipts forcefully adds a receipts to the block without a
|
||||
// backing transaction.
|
||||
//
|
||||
|
@ -582,3 +582,17 @@ func GetMipmapBloom(db ethdb.Database, number, level uint64) types.Bloom {
|
||||
bloomDat, _ := db.Get(mipmapKey(number, level))
|
||||
return types.BytesToBloom(bloomDat)
|
||||
}
|
||||
|
||||
// GetBlockChainVersion reads the version number from db.
|
||||
func GetBlockChainVersion(db ethdb.Database) int {
|
||||
var vsn uint
|
||||
enc, _ := db.Get([]byte("BlockchainVersion"))
|
||||
rlp.DecodeBytes(enc, &vsn)
|
||||
return int(vsn)
|
||||
}
|
||||
|
||||
// WriteBlockChainVersion writes vsn as the version number to db.
|
||||
func WriteBlockChainVersion(db ethdb.Database, vsn int) {
|
||||
enc, _ := rlp.EncodeToBytes(uint(vsn))
|
||||
db.Put([]byte("BlockchainVersion"), enc)
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func (self *StateDB) RawDump() World {
|
||||
it := self.trie.Iterator()
|
||||
for it.Next() {
|
||||
addr := self.trie.GetKey(it.Key)
|
||||
stateObject := NewStateObjectFromBytes(common.BytesToAddress(addr), it.Value, self.db)
|
||||
stateObject, _ := DecodeObject(common.BytesToAddress(addr), self.db, it.Value)
|
||||
|
||||
account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)}
|
||||
account.Storage = make(map[string]string)
|
||||
|
@ -19,17 +19,19 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
var emptyCodeHash = crypto.Sha3(nil)
|
||||
|
||||
type Code []byte
|
||||
|
||||
func (self Code) String() string {
|
||||
@ -56,8 +58,7 @@ func (self Storage) Copy() Storage {
|
||||
}
|
||||
|
||||
type StateObject struct {
|
||||
// State database for storing state changes
|
||||
db ethdb.Database
|
||||
db trie.Database // State database for storing state changes
|
||||
trie *trie.SecureTrie
|
||||
|
||||
// Address belonging to this account
|
||||
@ -83,39 +84,16 @@ type StateObject struct {
|
||||
dirty bool
|
||||
}
|
||||
|
||||
func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
|
||||
object := &StateObject{db: db, address: address, balance: new(big.Int), dirty: true}
|
||||
func NewStateObject(address common.Address, db trie.Database) *StateObject {
|
||||
object := &StateObject{
|
||||
db: db,
|
||||
address: address,
|
||||
balance: new(big.Int),
|
||||
dirty: true,
|
||||
codeHash: emptyCodeHash,
|
||||
storage: make(Storage),
|
||||
}
|
||||
object.trie, _ = trie.NewSecure(common.Hash{}, db)
|
||||
object.storage = make(Storage)
|
||||
return object
|
||||
}
|
||||
|
||||
func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) *StateObject {
|
||||
var extobject struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Root common.Hash
|
||||
CodeHash []byte
|
||||
}
|
||||
err := rlp.Decode(bytes.NewReader(data), &extobject)
|
||||
if err != nil {
|
||||
glog.Errorf("can't decode state object %x: %v", address, err)
|
||||
return nil
|
||||
}
|
||||
trie, err := trie.NewSecure(extobject.Root, db)
|
||||
if err != nil {
|
||||
// TODO: bubble this up or panic
|
||||
glog.Errorf("can't create account trie with root %x: %v", extobject.Root[:], err)
|
||||
return nil
|
||||
}
|
||||
|
||||
object := &StateObject{address: address, db: db}
|
||||
object.nonce = extobject.Nonce
|
||||
object.balance = extobject.Balance
|
||||
object.codeHash = extobject.CodeHash
|
||||
object.trie = trie
|
||||
object.storage = make(map[string]common.Hash)
|
||||
object.code, _ = db.Get(extobject.CodeHash)
|
||||
return object
|
||||
}
|
||||
|
||||
@ -172,7 +150,6 @@ func (self *StateObject) Update() {
|
||||
self.trie.Delete([]byte(key))
|
||||
continue
|
||||
}
|
||||
|
||||
self.setAddr([]byte(key), value)
|
||||
}
|
||||
}
|
||||
@ -248,6 +225,7 @@ func (self *StateObject) Code() []byte {
|
||||
|
||||
func (self *StateObject) SetCode(code []byte) {
|
||||
self.code = code
|
||||
self.codeHash = crypto.Sha3(code)
|
||||
self.dirty = true
|
||||
}
|
||||
|
||||
@ -276,23 +254,40 @@ func (self *StateObject) EachStorage(cb func(key, value []byte)) {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Encoding
|
||||
//
|
||||
|
||||
// State object encoding methods
|
||||
func (c *StateObject) RlpEncode() []byte {
|
||||
return common.Encode([]interface{}{c.nonce, c.balance, c.Root(), c.CodeHash()})
|
||||
type extStateObject struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Root common.Hash
|
||||
CodeHash []byte
|
||||
}
|
||||
|
||||
func (c *StateObject) CodeHash() common.Bytes {
|
||||
return crypto.Sha3(c.code)
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
func (c *StateObject) EncodeRLP(w io.Writer) error {
|
||||
return rlp.Encode(w, []interface{}{c.nonce, c.balance, c.Root(), c.codeHash})
|
||||
}
|
||||
|
||||
// Storage change object. Used by the manifest for notifying changes to
|
||||
// the sub channels.
|
||||
type StorageState struct {
|
||||
StateAddress []byte
|
||||
Address []byte
|
||||
Value *big.Int
|
||||
// DecodeObject decodes an RLP-encoded state object.
|
||||
func DecodeObject(address common.Address, db trie.Database, data []byte) (*StateObject, error) {
|
||||
var (
|
||||
obj = &StateObject{address: address, db: db, storage: make(Storage)}
|
||||
ext extStateObject
|
||||
err error
|
||||
)
|
||||
if err = rlp.DecodeBytes(data, &ext); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if obj.trie, err = trie.NewSecure(ext.Root, db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.Equal(ext.CodeHash, emptyCodeHash) {
|
||||
if obj.code, err = db.Get(ext.CodeHash); err != nil {
|
||||
return nil, fmt.Errorf("can't find code for hash %x: %v", ext.CodeHash, err)
|
||||
}
|
||||
}
|
||||
obj.nonce = ext.Nonce
|
||||
obj.balance = ext.Balance
|
||||
obj.codeHash = ext.CodeHash
|
||||
return obj, nil
|
||||
}
|
||||
|
@ -138,8 +138,7 @@ func TestSnapshot2(t *testing.T) {
|
||||
so0 := state.GetStateObject(stateobjaddr0)
|
||||
so0.balance = big.NewInt(42)
|
||||
so0.nonce = 43
|
||||
so0.code = []byte{'c', 'a', 'f', 'e'}
|
||||
so0.codeHash = so0.CodeHash()
|
||||
so0.SetCode([]byte{'c', 'a', 'f', 'e'})
|
||||
so0.remove = true
|
||||
so0.deleted = false
|
||||
so0.dirty = false
|
||||
@ -149,8 +148,7 @@ func TestSnapshot2(t *testing.T) {
|
||||
so1 := state.GetStateObject(stateobjaddr1)
|
||||
so1.balance = big.NewInt(52)
|
||||
so1.nonce = 53
|
||||
so1.code = []byte{'c', 'a', 'f', 'e', '2'}
|
||||
so1.codeHash = so1.CodeHash()
|
||||
so1.SetCode([]byte{'c', 'a', 'f', 'e', '2'})
|
||||
so1.remove = true
|
||||
so1.deleted = true
|
||||
so1.dirty = true
|
||||
|
@ -18,6 +18,7 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@ -25,6 +26,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
@ -205,13 +207,15 @@ func (self *StateDB) Delete(addr common.Address) bool {
|
||||
|
||||
// Update the given state object and apply it to state trie
|
||||
func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
||||
//addr := stateObject.Address()
|
||||
|
||||
if len(stateObject.CodeHash()) > 0 {
|
||||
self.db.Put(stateObject.CodeHash(), stateObject.code)
|
||||
if len(stateObject.code) > 0 {
|
||||
self.db.Put(stateObject.codeHash, stateObject.code)
|
||||
}
|
||||
addr := stateObject.Address()
|
||||
self.trie.Update(addr[:], stateObject.RlpEncode())
|
||||
data, err := rlp.EncodeToBytes(stateObject)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
|
||||
}
|
||||
self.trie.Update(addr[:], data)
|
||||
}
|
||||
|
||||
// Delete the given state object and delete it from the state trie
|
||||
@ -238,10 +242,12 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
stateObject = NewStateObjectFromBytes(addr, []byte(data), self.db)
|
||||
stateObject, err := DecodeObject(addr, self.db, data)
|
||||
if err != nil {
|
||||
glog.Errorf("can't decode object at %x: %v", addr[:], err)
|
||||
return nil
|
||||
}
|
||||
self.SetStateObject(stateObject)
|
||||
|
||||
return stateObject
|
||||
}
|
||||
|
||||
|
@ -125,17 +125,14 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||
// Receipts is a wrapper around a Receipt array to implement types.DerivableList.
|
||||
type Receipts []*Receipt
|
||||
|
||||
// RlpEncode implements common.RlpEncode required for SHA3 derivation.
|
||||
func (r Receipts) RlpEncode() []byte {
|
||||
bytes, err := rlp.EncodeToBytes(r)
|
||||
// Len returns the number of receipts in this list.
|
||||
func (r Receipts) Len() int { return len(r) }
|
||||
|
||||
// GetRlp returns the RLP encoding of one receipt from the list.
|
||||
func (r Receipts) GetRlp(i int) []byte {
|
||||
bytes, err := rlp.EncodeToBytes(r[i])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
// Len returns the number of receipts in this list.
|
||||
func (r Receipts) Len() int { return len(r) }
|
||||
|
||||
// GetRlp returns the RLP encoding of one receipt from the list.
|
||||
func (r Receipts) GetRlp(i int) []byte { return common.Rlp(r[i]) }
|
||||
|
@ -180,12 +180,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||
}
|
||||
|
||||
if !config.SkipBcVersionCheck {
|
||||
b, _ := chainDb.Get([]byte("BlockchainVersion"))
|
||||
bcVersion := int(common.NewValue(b).Uint())
|
||||
bcVersion := core.GetBlockChainVersion(chainDb)
|
||||
if bcVersion != config.BlockChainVersion && bcVersion != 0 {
|
||||
return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion)
|
||||
}
|
||||
saveBlockchainVersion(chainDb, config.BlockChainVersion)
|
||||
core.WriteBlockChainVersion(chainDb, config.BlockChainVersion)
|
||||
}
|
||||
glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
|
||||
|
||||
@ -479,15 +478,6 @@ func dagFiles(epoch uint64) (string, string) {
|
||||
return dag, "full-R" + dag
|
||||
}
|
||||
|
||||
func saveBlockchainVersion(db ethdb.Database, bcVersion int) {
|
||||
d, _ := db.Get([]byte("BlockchainVersion"))
|
||||
blockchainVersion := common.NewValue(d).Uint()
|
||||
|
||||
if blockchainVersion == 0 {
|
||||
db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// upgradeChainDatabase ensures that the chain database stores block split into
|
||||
// separate header and body entries.
|
||||
func upgradeChainDatabase(db ethdb.Database) error {
|
||||
|
@ -61,8 +61,11 @@ func makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Recei
|
||||
block.AddTx(tx)
|
||||
}
|
||||
// If the block number is a multiple of 5, add a bonus uncle to the block
|
||||
if i%5 == 0 {
|
||||
block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))})
|
||||
if i > 0 && i%5 == 0 {
|
||||
block.AddUncle(&types.Header{
|
||||
ParentHash: block.PrevBlock(i - 1).Hash(),
|
||||
Number: big.NewInt(block.Number().Int64() - 1),
|
||||
})
|
||||
}
|
||||
})
|
||||
// Convert the block-chain into a hash-chain and header/block maps
|
||||
|
@ -18,7 +18,6 @@ package ethdb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@ -90,27 +89,7 @@ func (db *MemDatabase) Delete(key []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *MemDatabase) Print() {
|
||||
db.lock.RLock()
|
||||
defer db.lock.RUnlock()
|
||||
|
||||
for key, val := range db.db {
|
||||
fmt.Printf("%x(%d): ", key, len(key))
|
||||
node := common.NewValueFromBytes(val)
|
||||
fmt.Printf("%q\n", node.Val)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *MemDatabase) Close() {
|
||||
}
|
||||
|
||||
func (db *MemDatabase) LastKnownTD() []byte {
|
||||
data, _ := db.Get([]byte("LastKnownTotalDifficulty"))
|
||||
if len(data) == 0 || data == nil {
|
||||
data = []byte{0x0}
|
||||
}
|
||||
return data
|
||||
}
|
||||
func (db *MemDatabase) Close() {}
|
||||
|
||||
func (db *MemDatabase) NewBatch() Batch {
|
||||
return &memBatch{db: db}
|
||||
|
@ -47,10 +47,6 @@ func (self *Object) StorageString(str string) []byte {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Object) StorageValue(addr *common.Value) []byte {
|
||||
return self.storage(addr.Bytes())
|
||||
}
|
||||
|
||||
func (self *Object) storage(addr []byte) []byte {
|
||||
return self.StateObject.GetState(common.BytesToHash(addr)).Bytes()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user