core/types: use package rlp instead of common.Decode

This commit is contained in:
Felix Lange 2015-03-18 13:24:34 +01:00
parent b94a6a0193
commit c298148a7f
4 changed files with 156 additions and 61 deletions

View File

@ -3,12 +3,13 @@ package types
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io"
"math/big" "math/big"
"sort" "sort"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -45,6 +46,14 @@ type Header struct {
Nonce [8]byte Nonce [8]byte
} }
func (self *Header) Hash() common.Hash {
return rlpHash(self.rlpData(true))
}
func (self *Header) HashNoNonce() common.Hash {
return rlpHash(self.rlpData(false))
}
func (self *Header) rlpData(withNonce bool) []interface{} { func (self *Header) rlpData(withNonce bool) []interface{} {
fields := []interface{}{ fields := []interface{}{
self.ParentHash, self.ParentHash,
@ -64,7 +73,6 @@ func (self *Header) rlpData(withNonce bool) []interface{} {
if withNonce { if withNonce {
fields = append(fields, self.MixDigest, self.Nonce) fields = append(fields, self.MixDigest, self.Nonce)
} }
return fields return fields
} }
@ -72,12 +80,11 @@ func (self *Header) RlpData() interface{} {
return self.rlpData(true) return self.rlpData(true)
} }
func (self *Header) Hash() common.Hash { func rlpHash(x interface{}) (h common.Hash) {
return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(true)))) hw := sha3.NewKeccak256()
} rlp.Encode(hw, x)
hw.Sum(h[:0])
func (self *Header) HashNoNonce() common.Hash { return h
return common.BytesToHash(crypto.Sha3(common.Encode(self.rlpData(false))))
} }
type Block struct { type Block struct {
@ -95,6 +102,26 @@ type Block struct {
Reward *big.Int Reward *big.Int
} }
// StorageBlock defines the RLP encoding of a Block stored in the
// state database. The StorageBlock encoding contains fields that
// would otherwise need to be recomputed.
type StorageBlock Block
// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
}
// "storage" block encoding. used for database.
type storageblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
TD *big.Int
}
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block { func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block {
header := &Header{ header := &Header{
Root: root, Root: root,
@ -107,9 +134,7 @@ func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash,
GasLimit: new(big.Int), GasLimit: new(big.Int),
} }
header.SetNonce(nonce) header.SetNonce(nonce)
block := &Block{header: header, Reward: new(big.Int)} block := &Block{header: header, Reward: new(big.Int)}
return block return block
} }
@ -122,22 +147,40 @@ func NewBlockWithHeader(header *Header) *Block {
} }
func (self *Block) DecodeRLP(s *rlp.Stream) error { func (self *Block) DecodeRLP(s *rlp.Stream) error {
var extblock struct { var eb extblock
Header *Header if err := s.Decode(&eb); err != nil {
Txs []*Transaction
Uncles []*Header
TD *big.Int // optional
}
if err := s.Decode(&extblock); err != nil {
return err return err
} }
self.header = extblock.Header self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs
self.uncles = extblock.Uncles
self.transactions = extblock.Txs
self.Td = extblock.TD
return nil return nil
} }
func (self Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, extblock{
Header: self.header,
Txs: self.transactions,
Uncles: self.uncles,
})
}
func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error {
var sb storageblock
if err := s.Decode(&sb); err != nil {
return err
}
self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD
return nil
}
func (self StorageBlock) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, storageblock{
Header: self.header,
Txs: self.transactions,
Uncles: self.uncles,
TD: self.Td,
})
}
func (self *Block) Header() *Header { func (self *Block) Header() *Header {
return self.header return self.header
} }
@ -148,7 +191,7 @@ func (self *Block) Uncles() []*Header {
func (self *Block) SetUncles(uncleHeaders []*Header) { func (self *Block) SetUncles(uncleHeaders []*Header) {
self.uncles = uncleHeaders self.uncles = uncleHeaders
self.header.UncleHash = common.BytesToHash(crypto.Sha3(common.Encode(uncleHeaders))) self.header.UncleHash = rlpHash(uncleHeaders)
} }
func (self *Block) Transactions() Transactions { func (self *Block) Transactions() Transactions {
@ -213,7 +256,6 @@ func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
func (self *Block) Root() common.Hash { return self.header.Root } func (self *Block) Root() common.Hash { return self.header.Root }
func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } func (self *Block) SetRoot(root common.Hash) { self.header.Root = root }
func (self *Block) Size() common.StorageSize { return common.StorageSize(len(common.Encode(self))) }
func (self *Block) GetTransaction(i int) *Transaction { func (self *Block) GetTransaction(i int) *Transaction {
if len(self.transactions) > i { if len(self.transactions) > i {
return self.transactions[i] return self.transactions[i]
@ -227,6 +269,19 @@ func (self *Block) GetUncle(i int) *Header {
return nil return nil
} }
func (self *Block) Size() common.StorageSize {
c := writeCounter(0)
rlp.Encode(&c, self)
return common.StorageSize(c)
}
type writeCounter common.StorageSize
func (c *writeCounter) Write(b []byte) (int, error) {
*c += writeCounter(len(b))
return len(b), nil
}
// Implement pow.Block // Implement pow.Block
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() }

View File

@ -1,19 +1,60 @@
package types package types
import ( import (
"bytes"
"math/big" "math/big"
"reflect"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
) )
// XXX Tests doesn't really do anything. This tests exists while working on the fixed size conversions // from bcValidBlockTest.json, "SimpleTx"
func TestConversion(t *testing.T) { func TestBlockEncoding(t *testing.T) {
var ( blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0")
parent common.Hash
coinbase common.Address
hash common.Hash
)
NewBlock(parent, coinbase, hash, big.NewInt(0), 0, "") var block Block
if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
t.Fatal("decode error: ", err)
}
check := func(f string, got, want interface{}) {
if !reflect.DeepEqual(got, want) {
t.Errorf("%s mismatch: got %v, want %v", f, got, want)
}
}
check("Difficulty", block.Difficulty(), big.NewInt(131072))
check("GasLimit", block.GasLimit(), big.NewInt(3141592))
check("GasUsed", block.GasUsed(), big.NewInt(21000))
check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e"))
check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
check("Time", block.Time(), int64(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
check("Transactions", block.Transactions(), Transactions{
{
Payload: []byte{},
Amount: big.NewInt(10),
Price: big.NewInt(10),
GasLimit: big.NewInt(50000),
AccountNonce: 0,
V: 27,
R: common.FromHex("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f"),
S: common.FromHex("8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"),
Recipient: &to,
},
})
ourBlockEnc, err := rlp.EncodeToBytes(&block)
if err != nil {
t.Fatal("encode error: ", err)
}
if !bytes.Equal(ourBlockEnc, blockEnc) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
}
} }

View File

@ -3,6 +3,7 @@ package types
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -15,7 +16,8 @@ func DeriveSha(list DerivableList) common.Hash {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
trie := trie.New(nil, db) trie := trie.New(nil, db)
for i := 0; i < list.Len(); i++ { for i := 0; i < list.Len(); i++ {
trie.Update(common.Encode(i), list.GetRlp(i)) key, _ := rlp.EncodeToBytes(i)
trie.Update(key, list.GetRlp(i))
} }
return common.BytesToHash(trie.Root()) return common.BytesToHash(trie.Root())

View File

@ -1,16 +1,14 @@
package types package types
import ( import (
"bytes" "crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"io"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -38,16 +36,18 @@ func NewTransactionMessage(to common.Address, amount, gasAmount, gasPrice *big.I
} }
func NewTransactionFromBytes(data []byte) *Transaction { func NewTransactionFromBytes(data []byte) *Transaction {
// TODO: remove this function if possible. callers would
// much better off decoding into transaction directly.
// it's not that hard.
tx := new(Transaction) tx := new(Transaction)
rlp.Decode(bytes.NewReader(data), tx) rlp.DecodeBytes(data, tx)
return tx return tx
} }
func (tx *Transaction) Hash() (a common.Hash) { func (tx *Transaction) Hash() common.Hash {
h := sha3.NewKeccak256() return rlpHash([]interface{}{
rlp.Encode(h, []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}) tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload,
h.Sum(a[:0]) })
return a
} }
func (self *Transaction) Data() []byte { func (self *Transaction) Data() []byte {
@ -122,17 +122,14 @@ func (tx *Transaction) SetSignatureValues(sig []byte) error {
return nil return nil
} }
func (tx Transaction) EncodeRLP(w io.Writer) error { func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) error {
return rlp.Encode(w, []interface{}{ h := tx.Hash()
tx.AccountNonce, sig, err := crypto.Sign(h[:], prv)
tx.Price, tx.GasLimit, if err != nil {
tx.Recipient, return err
tx.Amount, }
tx.Payload, tx.SetSignatureValues(sig)
tx.V, return nil
tx.R,
tx.S,
})
} }
// TODO: remove // TODO: remove
@ -141,11 +138,6 @@ func (tx *Transaction) RlpData() interface{} {
return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes()) return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes())
} }
// TODO: remove
func (tx *Transaction) RlpEncode() []byte {
return common.Encode(tx)
}
func (tx *Transaction) String() string { func (tx *Transaction) String() string {
var from, to string var from, to string
if f, err := tx.From(); err != nil { if f, err := tx.From(); err != nil {
@ -158,6 +150,7 @@ func (tx *Transaction) String() string {
} else { } else {
to = fmt.Sprintf("%x", t[:]) to = fmt.Sprintf("%x", t[:])
} }
enc, _ := rlp.EncodeToBytes(tx)
return fmt.Sprintf(` return fmt.Sprintf(`
TX(%x) TX(%x)
Contract: %v Contract: %v
@ -185,7 +178,7 @@ func (tx *Transaction) String() string {
tx.V, tx.V,
tx.R, tx.R,
tx.S, tx.S,
common.Encode(tx), enc,
) )
} }
@ -204,9 +197,13 @@ func (self Transactions) RlpData() interface{} {
return enc return enc
} }
func (s Transactions) Len() int { return len(s) } func (s Transactions) Len() int { return len(s) }
func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s Transactions) GetRlp(i int) []byte { return common.Rlp(s[i]) }
func (s Transactions) GetRlp(i int) []byte {
enc, _ := rlp.EncodeToBytes(s[i])
return enc
}
type TxByNonce struct{ Transactions } type TxByNonce struct{ Transactions }