diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 80f3777d6..868ee7db1 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -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 { diff --git a/common/package.go b/common/package.go deleted file mode 100644 index 4e8780c08..000000000 --- a/common/package.go +++ /dev/null @@ -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 . - -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 -} diff --git a/common/rlp.go b/common/rlp.go deleted file mode 100644 index 481b451b1..000000000 --- a/common/rlp.go +++ /dev/null @@ -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 . - -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 -} diff --git a/common/rlp_test.go b/common/rlp_test.go deleted file mode 100644 index 2320ffe3c..000000000 --- a/common/rlp_test.go +++ /dev/null @@ -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 . - -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) - } -} diff --git a/common/value.go b/common/value.go deleted file mode 100644 index 7abbf67b1..000000000 --- a/common/value.go +++ /dev/null @@ -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 . - -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 -} diff --git a/common/value_test.go b/common/value_test.go deleted file mode 100644 index ac2ef02a7..000000000 --- a/common/value_test.go +++ /dev/null @@ -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 . - -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) -} diff --git a/core/chain_makers.go b/core/chain_makers.go index 4f6fa3989..5a8f380a3 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -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. // diff --git a/core/database_util.go b/core/database_util.go index fbcce3e8c..2dc113e29 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -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) +} diff --git a/core/state/dump.go b/core/state/dump.go index 9acb8a024..cff9c50aa 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -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) diff --git a/core/state/state_object.go b/core/state/state_object.go index c06e3d227..47546112f 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -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 } diff --git a/core/state/state_test.go b/core/state/state_test.go index 7ddbe11a1..7ce341c36 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -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 diff --git a/core/state/statedb.go b/core/state/statedb.go index a9de71409..ab93870bf 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -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 } diff --git a/core/types/receipt.go b/core/types/receipt.go index e7d5203a3..5f847fc5c 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -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]) } diff --git a/eth/backend.go b/eth/backend.go index d51446d51..abd1214ca 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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 { diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index cfcc8a2ef..f02418a2f 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -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 diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index 01273b9db..45423ed73 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -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} diff --git a/xeth/types.go b/xeth/types.go index 218c8dc7c..090115b7e 100644 --- a/xeth/types.go +++ b/xeth/types.go @@ -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() }