aboutsummaryrefslogtreecommitdiff
path: root/core/types
diff options
context:
space:
mode:
Diffstat (limited to 'core/types')
-rw-r--r--core/types/block.go492
-rw-r--r--core/types/bloom9.go136
-rw-r--r--core/types/derive_sha.go41
-rw-r--r--core/types/gen_header_json.go138
-rw-r--r--core/types/gen_log_json.go92
-rw-r--r--core/types/gen_receipt_json.go104
-rw-r--r--core/types/gen_tx_json.go101
-rw-r--r--core/types/log.go143
-rw-r--r--core/types/receipt.go336
-rw-r--r--core/types/transaction.go419
-rw-r--r--core/types/transaction_signing.go260
11 files changed, 2262 insertions, 0 deletions
diff --git a/core/types/block.go b/core/types/block.go
new file mode 100644
index 0000000..4096d86
--- /dev/null
+++ b/core/types/block.go
@@ -0,0 +1,492 @@
+// 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 types contains data types related to Ethereum consensus.
+package types
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math/big"
+ "reflect"
+ "sort"
+ "sync/atomic"
+ "time"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/rlp"
+ "golang.org/x/crypto/sha3"
+)
+
+var (
+ EmptyRootHash = DeriveSha(Transactions{})
+ EmptyUncleHash = rlpHash([]*Header(nil))
+)
+
+// A BlockNonce is a 64-bit hash which proves (combined with the
+// mix-hash) that a sufficient amount of computation has been carried
+// out on a block.
+type BlockNonce [8]byte
+
+// EncodeNonce converts the given integer to a block nonce.
+func EncodeNonce(i uint64) BlockNonce {
+ var n BlockNonce
+ binary.BigEndian.PutUint64(n[:], i)
+ return n
+}
+
+// Uint64 returns the integer value of a block nonce.
+func (n BlockNonce) Uint64() uint64 {
+ return binary.BigEndian.Uint64(n[:])
+}
+
+// MarshalText encodes n as a hex string with 0x prefix.
+func (n BlockNonce) MarshalText() ([]byte, error) {
+ return hexutil.Bytes(n[:]).MarshalText()
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (n *BlockNonce) UnmarshalText(input []byte) error {
+ return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
+}
+
+//go:generate gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
+
+// Header represents a block header in the Ethereum blockchain.
+type Header struct {
+ ParentHash common.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase common.Address `json:"miner" gencodec:"required"`
+ Root common.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *big.Int `json:"difficulty" gencodec:"required"`
+ Number *big.Int `json:"number" gencodec:"required"`
+ GasLimit uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed uint64 `json:"gasUsed" gencodec:"required"`
+ Time uint64 `json:"timestamp" gencodec:"required"`
+ Extra []byte `json:"extraData" gencodec:"required"`
+ MixDigest common.Hash `json:"mixHash"`
+ Nonce BlockNonce `json:"nonce"`
+ ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"`
+}
+
+// field type overrides for gencodec
+type headerMarshaling struct {
+ Difficulty *hexutil.Big
+ Number *hexutil.Big
+ GasLimit hexutil.Uint64
+ GasUsed hexutil.Uint64
+ Time hexutil.Uint64
+ Extra hexutil.Bytes
+ Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
+}
+
+// Hash returns the block hash of the header, which is simply the keccak256 hash of its
+// RLP encoding.
+func (h *Header) Hash() common.Hash {
+ return rlpHash(h)
+}
+
+var headerSize = common.StorageSize(reflect.TypeOf(Header{}).Size())
+
+// Size returns the approximate memory used by all internal contents. It is used
+// to approximate and limit the memory consumption of various caches.
+func (h *Header) Size() common.StorageSize {
+ return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen())/8)
+}
+
+// SanityCheck checks a few basic things -- these checks are way beyond what
+// any 'sane' production values should hold, and can mainly be used to prevent
+// that the unbounded fields are stuffed with junk data to add processing
+// overhead
+func (h *Header) SanityCheck() error {
+ if h.Number != nil && !h.Number.IsUint64() {
+ return fmt.Errorf("too large block number: bitlen %d", h.Number.BitLen())
+ }
+ if h.Difficulty != nil {
+ if diffLen := h.Difficulty.BitLen(); diffLen > 80 {
+ return fmt.Errorf("too large block difficulty: bitlen %d", diffLen)
+ }
+ }
+ if eLen := len(h.Extra); eLen > 100*1024 {
+ return fmt.Errorf("too large block extradata: size %d", eLen)
+ }
+ return nil
+}
+
+func rlpHash(x interface{}) (h common.Hash) {
+ hw := sha3.NewLegacyKeccak256()
+ rlp.Encode(hw, x)
+ hw.Sum(h[:0])
+ return h
+}
+
+// Body is a simple (mutable, non-safe) data container for storing and moving
+// a block's data contents (transactions and uncles) together.
+type Body struct {
+ Transactions []*Transaction
+ Uncles []*Header
+ Version uint32
+ ExtData []byte `rlp:"nil"`
+}
+
+// Block represents an entire block in the Ethereum blockchain.
+type Block struct {
+ header *Header
+ uncles []*Header
+ transactions Transactions
+ version uint32
+ extdata []byte
+
+ // caches
+ hash atomic.Value
+ size atomic.Value
+
+ // Td is used by package core to store the total difficulty
+ // of the chain up to and including the block.
+ td *big.Int
+
+ // These fields are used by package eth to track
+ // inter-peer block relay.
+ ReceivedAt time.Time
+ ReceivedFrom interface{}
+}
+
+// DeprecatedTd is an old relic for extracting the TD of a block. It is in the
+// code solely to facilitate upgrading the database from the old format to the
+// new, after which it should be deleted. Do not use!
+func (b *Block) DeprecatedTd() *big.Int {
+ return b.td
+}
+
+// [deprecated by eth/63]
+// 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
+}
+
+type myextblock struct {
+ Header *Header
+ Txs []*Transaction
+ Uncles []*Header
+ Version uint32
+ ExtData []byte `rlp:"nil"`
+}
+
+// [deprecated by eth/63]
+// "storage" block encoding. used for database.
+type storageblock struct {
+ Header *Header
+ Txs []*Transaction
+ Uncles []*Header
+ TD *big.Int
+}
+
+// NewBlock creates a new block. The input data is copied,
+// changes to header and to the field values will not affect the
+// block.
+//
+// The values of TxHash, UncleHash, ReceiptHash and Bloom in header
+// are ignored and set to values derived from the given txs, uncles
+// and receipts.
+func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, extdata []byte) *Block {
+ b := &Block{header: CopyHeader(header), td: new(big.Int)}
+
+ // TODO: panic if len(txs) != len(receipts)
+ if len(txs) == 0 {
+ b.header.TxHash = EmptyRootHash
+ } else {
+ b.header.TxHash = DeriveSha(Transactions(txs))
+ b.transactions = make(Transactions, len(txs))
+ copy(b.transactions, txs)
+ }
+
+ if len(receipts) == 0 {
+ b.header.ReceiptHash = EmptyRootHash
+ } else {
+ b.header.ReceiptHash = DeriveSha(Receipts(receipts))
+ b.header.Bloom = CreateBloom(receipts)
+ }
+
+ if len(uncles) == 0 {
+ b.header.UncleHash = EmptyUncleHash
+ } else {
+ b.header.UncleHash = CalcUncleHash(uncles)
+ b.uncles = make([]*Header, len(uncles))
+ for i := range uncles {
+ b.uncles[i] = CopyHeader(uncles[i])
+ }
+ }
+
+ b.extdata = make([]byte, len(extdata))
+ copy(b.extdata, extdata)
+
+ return b
+}
+
+// NewBlockWithHeader creates a block with the given header data. The
+// header data is copied, changes to header and to the field values
+// will not affect the block.
+func NewBlockWithHeader(header *Header) *Block {
+ return &Block{header: CopyHeader(header)}
+}
+
+// CopyHeader creates a deep copy of a block header to prevent side effects from
+// modifying a header variable.
+func CopyHeader(h *Header) *Header {
+ cpy := *h
+ if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
+ cpy.Difficulty.Set(h.Difficulty)
+ }
+ if cpy.Number = new(big.Int); h.Number != nil {
+ cpy.Number.Set(h.Number)
+ }
+ if len(h.Extra) > 0 {
+ cpy.Extra = make([]byte, len(h.Extra))
+ copy(cpy.Extra, h.Extra)
+ }
+ return &cpy
+}
+
+// DecodeRLP decodes the Ethereum
+func (b *Block) DecodeRLP(s *rlp.Stream) error {
+ bs, _ := s.Raw()
+ copied := make([]byte, len(bs))
+ copy(copied, bs)
+ ss := rlp.NewStream(bytes.NewReader(bs), 0)
+
+ var eb extblock
+ _, size, _ := ss.Kind()
+ if err := ss.Decode(&eb); err != nil {
+ var meb myextblock
+ ss = rlp.NewStream(bytes.NewReader(copied), 0)
+ if err := ss.Decode(&meb); err != nil {
+ return err
+ }
+ b.header, b.uncles, b.transactions = meb.Header, meb.Uncles, meb.Txs
+ b.extdata = meb.ExtData
+ } else {
+ b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs
+ b.extdata = nil
+ }
+ b.hash = atomic.Value{}
+ b.size.Store(common.StorageSize(rlp.ListSize(size)))
+ return nil
+}
+
+func (b *Block) SetExtraData(data []byte) {
+ b.extdata = data
+ b.header.ExtDataHash = rlpHash(data)
+ b.hash = atomic.Value{}
+}
+
+func (b *Block) ExtraData() []byte {
+ return b.extdata
+}
+
+func (b *Block) SetVersion(ver uint32) {
+ b.version = ver
+}
+
+func (b *Block) Version() uint32 {
+ return b.version
+}
+
+// EncodeRLPEth serializes b into the Ethereum RLP block format.
+func (b *Block) EncodeRLPEth(w io.Writer) error {
+ return rlp.Encode(w, extblock{
+ Header: b.header,
+ Txs: b.transactions,
+ Uncles: b.uncles,
+ })
+}
+
+func (b *Block) EncodeRLPTest(w io.Writer, ver uint32) error {
+ return rlp.Encode(w, myextblock{
+ Header: b.header,
+ Txs: b.transactions,
+ Uncles: b.uncles,
+ Version: ver,
+ ExtData: b.extdata,
+ })
+}
+
+// EncodeRLP serializes b into an extended format.
+func (b *Block) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, myextblock{
+ Header: b.header,
+ Txs: b.transactions,
+ Uncles: b.uncles,
+ Version: b.version,
+ ExtData: b.extdata,
+ })
+}
+
+// [deprecated by eth/63]
+func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
+ var sb storageblock
+ if err := s.Decode(&sb); err != nil {
+ return err
+ }
+ b.header, b.uncles, b.transactions, b.td = sb.Header, sb.Uncles, sb.Txs, sb.TD
+ return nil
+}
+
+// TODO: copies
+
+func (b *Block) Uncles() []*Header { return b.uncles }
+func (b *Block) Transactions() Transactions { return b.transactions }
+
+func (b *Block) Transaction(hash common.Hash) *Transaction {
+ for _, transaction := range b.transactions {
+ if transaction.Hash() == hash {
+ return transaction
+ }
+ }
+ return nil
+}
+
+func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
+func (b *Block) GasLimit() uint64 { return b.header.GasLimit }
+func (b *Block) GasUsed() uint64 { return b.header.GasUsed }
+func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
+func (b *Block) Time() uint64 { return b.header.Time }
+
+func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
+func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
+func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
+func (b *Block) Bloom() Bloom { return b.header.Bloom }
+func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
+func (b *Block) Root() common.Hash { return b.header.Root }
+func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
+func (b *Block) TxHash() common.Hash { return b.header.TxHash }
+func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
+func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
+func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
+
+func (b *Block) Header() *Header { return CopyHeader(b.header) }
+
+// Body returns the non-header content of the block.
+func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.version, b.extdata} }
+
+// Size returns the true RLP encoded storage size of the block, either by encoding
+// and returning it, or returning a previsouly cached value.
+func (b *Block) Size() common.StorageSize {
+ if size := b.size.Load(); size != nil {
+ return size.(common.StorageSize)
+ }
+ c := writeCounter(0)
+ rlp.Encode(&c, b)
+ b.size.Store(common.StorageSize(c))
+ return common.StorageSize(c)
+}
+
+// SanityCheck can be used to prevent that unbounded fields are
+// stuffed with junk data to add processing overhead
+func (b *Block) SanityCheck() error {
+ return b.header.SanityCheck()
+}
+
+type writeCounter common.StorageSize
+
+func (c *writeCounter) Write(b []byte) (int, error) {
+ *c += writeCounter(len(b))
+ return len(b), nil
+}
+
+func CalcUncleHash(uncles []*Header) common.Hash {
+ if len(uncles) == 0 {
+ return EmptyUncleHash
+ }
+ return rlpHash(uncles)
+}
+
+// WithSeal returns a new block with the data from b but the header replaced with
+// the sealed one.
+func (b *Block) WithSeal(header *Header) *Block {
+ cpy := *header
+
+ return &Block{
+ header: &cpy,
+ transactions: b.transactions,
+ uncles: b.uncles,
+ }
+}
+
+// WithBody returns a new block with the given transaction and uncle contents.
+func (b *Block) WithBody(transactions []*Transaction, uncles []*Header, version uint32, extdata []byte) *Block {
+ block := &Block{
+ header: CopyHeader(b.header),
+ transactions: make([]*Transaction, len(transactions)),
+ uncles: make([]*Header, len(uncles)),
+ extdata: make([]byte, len(extdata)),
+ version: version,
+ }
+ copy(block.transactions, transactions)
+ copy(block.extdata, extdata)
+ for i := range uncles {
+ block.uncles[i] = CopyHeader(uncles[i])
+ }
+ return block
+}
+
+// Hash returns the keccak256 hash of b's header.
+// The hash is computed on the first call and cached thereafter.
+func (b *Block) Hash() common.Hash {
+ if hash := b.hash.Load(); hash != nil {
+ return hash.(common.Hash)
+ }
+ v := b.header.Hash()
+ b.hash.Store(v)
+ return v
+}
+
+type Blocks []*Block
+
+type BlockBy func(b1, b2 *Block) bool
+
+func (self BlockBy) Sort(blocks Blocks) {
+ bs := blockSorter{
+ blocks: blocks,
+ by: self,
+ }
+ sort.Sort(bs)
+}
+
+type blockSorter struct {
+ blocks Blocks
+ by func(b1, b2 *Block) bool
+}
+
+func (self blockSorter) Len() int { return len(self.blocks) }
+func (self blockSorter) Swap(i, j int) {
+ self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i]
+}
+func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
+
+func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 }
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
new file mode 100644
index 0000000..76923c4
--- /dev/null
+++ b/core/types/bloom9.go
@@ -0,0 +1,136 @@
+// 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 types
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/crypto"
+)
+
+type bytesBacked interface {
+ Bytes() []byte
+}
+
+const (
+ // BloomByteLength represents the number of bytes used in a header log bloom.
+ BloomByteLength = 256
+
+ // BloomBitLength represents the number of bits used in a header log bloom.
+ BloomBitLength = 8 * BloomByteLength
+)
+
+// Bloom represents a 2048 bit bloom filter.
+type Bloom [BloomByteLength]byte
+
+// BytesToBloom converts a byte slice to a bloom filter.
+// It panics if b is not of suitable size.
+func BytesToBloom(b []byte) Bloom {
+ var bloom Bloom
+ bloom.SetBytes(b)
+ return bloom
+}
+
+// SetBytes sets the content of b to the given bytes.
+// It panics if d is not of suitable size.
+func (b *Bloom) SetBytes(d []byte) {
+ if len(b) < len(d) {
+ panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d)))
+ }
+ copy(b[BloomByteLength-len(d):], d)
+}
+
+// Add adds d to the filter. Future calls of Test(d) will return true.
+func (b *Bloom) Add(d *big.Int) {
+ bin := new(big.Int).SetBytes(b[:])
+ bin.Or(bin, bloom9(d.Bytes()))
+ b.SetBytes(bin.Bytes())
+}
+
+// Big converts b to a big integer.
+func (b Bloom) Big() *big.Int {
+ return new(big.Int).SetBytes(b[:])
+}
+
+func (b Bloom) Bytes() []byte {
+ return b[:]
+}
+
+func (b Bloom) Test(test *big.Int) bool {
+ return BloomLookup(b, test)
+}
+
+func (b Bloom) TestBytes(test []byte) bool {
+ return b.Test(new(big.Int).SetBytes(test))
+
+}
+
+// MarshalText encodes b as a hex string with 0x prefix.
+func (b Bloom) MarshalText() ([]byte, error) {
+ return hexutil.Bytes(b[:]).MarshalText()
+}
+
+// UnmarshalText b as a hex string with 0x prefix.
+func (b *Bloom) UnmarshalText(input []byte) error {
+ return hexutil.UnmarshalFixedText("Bloom", input, b[:])
+}
+
+func CreateBloom(receipts Receipts) Bloom {
+ bin := new(big.Int)
+ for _, receipt := range receipts {
+ bin.Or(bin, LogsBloom(receipt.Logs))
+ }
+
+ return BytesToBloom(bin.Bytes())
+}
+
+func LogsBloom(logs []*Log) *big.Int {
+ bin := new(big.Int)
+ for _, log := range logs {
+ bin.Or(bin, bloom9(log.Address.Bytes()))
+ for _, b := range log.Topics {
+ bin.Or(bin, bloom9(b[:]))
+ }
+ }
+
+ return bin
+}
+
+func bloom9(b []byte) *big.Int {
+ b = crypto.Keccak256(b)
+
+ r := new(big.Int)
+
+ for i := 0; i < 6; i += 2 {
+ t := big.NewInt(1)
+ b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 2047
+ r.Or(r, t.Lsh(t, b))
+ }
+
+ return r
+}
+
+var Bloom9 = bloom9
+
+func BloomLookup(bin Bloom, topic bytesBacked) bool {
+ bloom := bin.Big()
+ cmp := bloom9(topic.Bytes())
+
+ return bloom.And(bloom, cmp).Cmp(cmp) == 0
+}
diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go
new file mode 100644
index 0000000..8234191
--- /dev/null
+++ b/core/types/derive_sha.go
@@ -0,0 +1,41 @@
+// 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 types
+
+import (
+ "bytes"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/rlp"
+ "github.com/ava-labs/go-ethereum/trie"
+)
+
+type DerivableList interface {
+ Len() int
+ GetRlp(i int) []byte
+}
+
+func DeriveSha(list DerivableList) common.Hash {
+ keybuf := new(bytes.Buffer)
+ trie := new(trie.Trie)
+ for i := 0; i < list.Len(); i++ {
+ keybuf.Reset()
+ rlp.Encode(keybuf, uint(i))
+ trie.Update(keybuf.Bytes(), list.GetRlp(i))
+ }
+ return trie.Hash()
+}
diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go
new file mode 100644
index 0000000..48b35db
--- /dev/null
+++ b/core/types/gen_header_json.go
@@ -0,0 +1,138 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+)
+
+var _ = (*headerMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (h Header) MarshalJSON() ([]byte, error) {
+ type Header struct {
+ ParentHash common.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase common.Address `json:"miner" gencodec:"required"`
+ Root common.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
+ Number *hexutil.Big `json:"number" gencodec:"required"`
+ GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
+ Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
+ MixDigest common.Hash `json:"mixHash"`
+ Nonce BlockNonce `json:"nonce"`
+ Hash common.Hash `json:"hash"`
+ }
+ var enc Header
+ enc.ParentHash = h.ParentHash
+ enc.UncleHash = h.UncleHash
+ enc.Coinbase = h.Coinbase
+ enc.Root = h.Root
+ enc.TxHash = h.TxHash
+ enc.ReceiptHash = h.ReceiptHash
+ enc.Bloom = h.Bloom
+ enc.Difficulty = (*hexutil.Big)(h.Difficulty)
+ enc.Number = (*hexutil.Big)(h.Number)
+ enc.GasLimit = hexutil.Uint64(h.GasLimit)
+ enc.GasUsed = hexutil.Uint64(h.GasUsed)
+ enc.Time = hexutil.Uint64(h.Time)
+ enc.Extra = h.Extra
+ enc.MixDigest = h.MixDigest
+ enc.Nonce = h.Nonce
+ enc.Hash = h.Hash()
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (h *Header) UnmarshalJSON(input []byte) error {
+ type Header struct {
+ ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
+ UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
+ Coinbase *common.Address `json:"miner" gencodec:"required"`
+ Root *common.Hash `json:"stateRoot" gencodec:"required"`
+ TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
+ ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
+ Bloom *Bloom `json:"logsBloom" gencodec:"required"`
+ Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
+ Number *hexutil.Big `json:"number" gencodec:"required"`
+ GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
+ GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
+ Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
+ MixDigest *common.Hash `json:"mixHash"`
+ Nonce *BlockNonce `json:"nonce"`
+ }
+ var dec Header
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.ParentHash == nil {
+ return errors.New("missing required field 'parentHash' for Header")
+ }
+ h.ParentHash = *dec.ParentHash
+ if dec.UncleHash == nil {
+ return errors.New("missing required field 'sha3Uncles' for Header")
+ }
+ h.UncleHash = *dec.UncleHash
+ if dec.Coinbase == nil {
+ return errors.New("missing required field 'miner' for Header")
+ }
+ h.Coinbase = *dec.Coinbase
+ if dec.Root == nil {
+ return errors.New("missing required field 'stateRoot' for Header")
+ }
+ h.Root = *dec.Root
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionsRoot' for Header")
+ }
+ h.TxHash = *dec.TxHash
+ if dec.ReceiptHash == nil {
+ return errors.New("missing required field 'receiptsRoot' for Header")
+ }
+ h.ReceiptHash = *dec.ReceiptHash
+ if dec.Bloom == nil {
+ return errors.New("missing required field 'logsBloom' for Header")
+ }
+ h.Bloom = *dec.Bloom
+ if dec.Difficulty == nil {
+ return errors.New("missing required field 'difficulty' for Header")
+ }
+ h.Difficulty = (*big.Int)(dec.Difficulty)
+ if dec.Number == nil {
+ return errors.New("missing required field 'number' for Header")
+ }
+ h.Number = (*big.Int)(dec.Number)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gasLimit' for Header")
+ }
+ h.GasLimit = uint64(*dec.GasLimit)
+ if dec.GasUsed == nil {
+ return errors.New("missing required field 'gasUsed' for Header")
+ }
+ h.GasUsed = uint64(*dec.GasUsed)
+ if dec.Time == nil {
+ return errors.New("missing required field 'timestamp' for Header")
+ }
+ h.Time = uint64(*dec.Time)
+ if dec.Extra == nil {
+ return errors.New("missing required field 'extraData' for Header")
+ }
+ h.Extra = *dec.Extra
+ if dec.MixDigest != nil {
+ h.MixDigest = *dec.MixDigest
+ }
+ if dec.Nonce != nil {
+ h.Nonce = *dec.Nonce
+ }
+ return nil
+}
diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go
new file mode 100644
index 0000000..0e48863
--- /dev/null
+++ b/core/types/gen_log_json.go
@@ -0,0 +1,92 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+)
+
+var _ = (*logMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (l Log) MarshalJSON() ([]byte, error) {
+ type Log struct {
+ Address common.Address `json:"address" gencodec:"required"`
+ Topics []common.Hash `json:"topics" gencodec:"required"`
+ Data hexutil.Bytes `json:"data" gencodec:"required"`
+ BlockNumber hexutil.Uint64 `json:"blockNumber"`
+ TxHash common.Hash `json:"transactionHash" gencodec:"required"`
+ TxIndex hexutil.Uint `json:"transactionIndex" gencodec:"required"`
+ BlockHash common.Hash `json:"blockHash"`
+ Index hexutil.Uint `json:"logIndex" gencodec:"required"`
+ Removed bool `json:"removed"`
+ }
+ var enc Log
+ enc.Address = l.Address
+ enc.Topics = l.Topics
+ enc.Data = l.Data
+ enc.BlockNumber = hexutil.Uint64(l.BlockNumber)
+ enc.TxHash = l.TxHash
+ enc.TxIndex = hexutil.Uint(l.TxIndex)
+ enc.BlockHash = l.BlockHash
+ enc.Index = hexutil.Uint(l.Index)
+ enc.Removed = l.Removed
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (l *Log) UnmarshalJSON(input []byte) error {
+ type Log struct {
+ Address *common.Address `json:"address" gencodec:"required"`
+ Topics []common.Hash `json:"topics" gencodec:"required"`
+ Data *hexutil.Bytes `json:"data" gencodec:"required"`
+ BlockNumber *hexutil.Uint64 `json:"blockNumber"`
+ TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
+ TxIndex *hexutil.Uint `json:"transactionIndex" gencodec:"required"`
+ BlockHash *common.Hash `json:"blockHash"`
+ Index *hexutil.Uint `json:"logIndex" gencodec:"required"`
+ Removed *bool `json:"removed"`
+ }
+ var dec Log
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Address == nil {
+ return errors.New("missing required field 'address' for Log")
+ }
+ l.Address = *dec.Address
+ if dec.Topics == nil {
+ return errors.New("missing required field 'topics' for Log")
+ }
+ l.Topics = dec.Topics
+ if dec.Data == nil {
+ return errors.New("missing required field 'data' for Log")
+ }
+ l.Data = *dec.Data
+ if dec.BlockNumber != nil {
+ l.BlockNumber = uint64(*dec.BlockNumber)
+ }
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionHash' for Log")
+ }
+ l.TxHash = *dec.TxHash
+ if dec.TxIndex == nil {
+ return errors.New("missing required field 'transactionIndex' for Log")
+ }
+ l.TxIndex = uint(*dec.TxIndex)
+ if dec.BlockHash != nil {
+ l.BlockHash = *dec.BlockHash
+ }
+ if dec.Index == nil {
+ return errors.New("missing required field 'logIndex' for Log")
+ }
+ l.Index = uint(*dec.Index)
+ if dec.Removed != nil {
+ l.Removed = *dec.Removed
+ }
+ return nil
+}
diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go
new file mode 100644
index 0000000..f7cde61
--- /dev/null
+++ b/core/types/gen_receipt_json.go
@@ -0,0 +1,104 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+)
+
+var _ = (*receiptMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (r Receipt) MarshalJSON() ([]byte, error) {
+ type Receipt struct {
+ PostState hexutil.Bytes `json:"root"`
+ Status hexutil.Uint64 `json:"status"`
+ CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Logs []*Log `json:"logs" gencodec:"required"`
+ TxHash common.Hash `json:"transactionHash" gencodec:"required"`
+ ContractAddress common.Address `json:"contractAddress"`
+ GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ BlockHash common.Hash `json:"blockHash,omitempty"`
+ BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
+ TransactionIndex hexutil.Uint `json:"transactionIndex"`
+ }
+ var enc Receipt
+ enc.PostState = r.PostState
+ enc.Status = hexutil.Uint64(r.Status)
+ enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed)
+ enc.Bloom = r.Bloom
+ enc.Logs = r.Logs
+ enc.TxHash = r.TxHash
+ enc.ContractAddress = r.ContractAddress
+ enc.GasUsed = hexutil.Uint64(r.GasUsed)
+ enc.BlockHash = r.BlockHash
+ enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
+ enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (r *Receipt) UnmarshalJSON(input []byte) error {
+ type Receipt struct {
+ PostState *hexutil.Bytes `json:"root"`
+ Status *hexutil.Uint64 `json:"status"`
+ CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
+ Bloom *Bloom `json:"logsBloom" gencodec:"required"`
+ Logs []*Log `json:"logs" gencodec:"required"`
+ TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
+ ContractAddress *common.Address `json:"contractAddress"`
+ GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
+ BlockHash *common.Hash `json:"blockHash,omitempty"`
+ BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
+ TransactionIndex *hexutil.Uint `json:"transactionIndex"`
+ }
+ var dec Receipt
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.PostState != nil {
+ r.PostState = *dec.PostState
+ }
+ if dec.Status != nil {
+ r.Status = uint64(*dec.Status)
+ }
+ if dec.CumulativeGasUsed == nil {
+ return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
+ }
+ r.CumulativeGasUsed = uint64(*dec.CumulativeGasUsed)
+ if dec.Bloom == nil {
+ return errors.New("missing required field 'logsBloom' for Receipt")
+ }
+ r.Bloom = *dec.Bloom
+ if dec.Logs == nil {
+ return errors.New("missing required field 'logs' for Receipt")
+ }
+ r.Logs = dec.Logs
+ if dec.TxHash == nil {
+ return errors.New("missing required field 'transactionHash' for Receipt")
+ }
+ r.TxHash = *dec.TxHash
+ if dec.ContractAddress != nil {
+ r.ContractAddress = *dec.ContractAddress
+ }
+ if dec.GasUsed == nil {
+ return errors.New("missing required field 'gasUsed' for Receipt")
+ }
+ r.GasUsed = uint64(*dec.GasUsed)
+ if dec.BlockHash != nil {
+ r.BlockHash = *dec.BlockHash
+ }
+ if dec.BlockNumber != nil {
+ r.BlockNumber = (*big.Int)(dec.BlockNumber)
+ }
+ if dec.TransactionIndex != nil {
+ r.TransactionIndex = uint(*dec.TransactionIndex)
+ }
+ return nil
+}
diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go
new file mode 100644
index 0000000..0410632
--- /dev/null
+++ b/core/types/gen_tx_json.go
@@ -0,0 +1,101 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package types
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+)
+
+var _ = (*txdataMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (t txdata) MarshalJSON() ([]byte, error) {
+ type txdata struct {
+ AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
+ Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
+ GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"`
+ Recipient *common.Address `json:"to" rlp:"nil"`
+ Amount *hexutil.Big `json:"value" gencodec:"required"`
+ Payload hexutil.Bytes `json:"input" gencodec:"required"`
+ V *hexutil.Big `json:"v" gencodec:"required"`
+ R *hexutil.Big `json:"r" gencodec:"required"`
+ S *hexutil.Big `json:"s" gencodec:"required"`
+ Hash *common.Hash `json:"hash" rlp:"-"`
+ }
+ var enc txdata
+ enc.AccountNonce = hexutil.Uint64(t.AccountNonce)
+ enc.Price = (*hexutil.Big)(t.Price)
+ enc.GasLimit = hexutil.Uint64(t.GasLimit)
+ enc.Recipient = t.Recipient
+ enc.Amount = (*hexutil.Big)(t.Amount)
+ enc.Payload = t.Payload
+ enc.V = (*hexutil.Big)(t.V)
+ enc.R = (*hexutil.Big)(t.R)
+ enc.S = (*hexutil.Big)(t.S)
+ enc.Hash = t.Hash
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (t *txdata) UnmarshalJSON(input []byte) error {
+ type txdata struct {
+ AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
+ Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
+ GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"`
+ Recipient *common.Address `json:"to" rlp:"nil"`
+ Amount *hexutil.Big `json:"value" gencodec:"required"`
+ Payload *hexutil.Bytes `json:"input" gencodec:"required"`
+ V *hexutil.Big `json:"v" gencodec:"required"`
+ R *hexutil.Big `json:"r" gencodec:"required"`
+ S *hexutil.Big `json:"s" gencodec:"required"`
+ Hash *common.Hash `json:"hash" rlp:"-"`
+ }
+ var dec txdata
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.AccountNonce == nil {
+ return errors.New("missing required field 'nonce' for txdata")
+ }
+ t.AccountNonce = uint64(*dec.AccountNonce)
+ if dec.Price == nil {
+ return errors.New("missing required field 'gasPrice' for txdata")
+ }
+ t.Price = (*big.Int)(dec.Price)
+ if dec.GasLimit == nil {
+ return errors.New("missing required field 'gas' for txdata")
+ }
+ t.GasLimit = uint64(*dec.GasLimit)
+ if dec.Recipient != nil {
+ t.Recipient = dec.Recipient
+ }
+ if dec.Amount == nil {
+ return errors.New("missing required field 'value' for txdata")
+ }
+ t.Amount = (*big.Int)(dec.Amount)
+ if dec.Payload == nil {
+ return errors.New("missing required field 'input' for txdata")
+ }
+ t.Payload = *dec.Payload
+ if dec.V == nil {
+ return errors.New("missing required field 'v' for txdata")
+ }
+ t.V = (*big.Int)(dec.V)
+ if dec.R == nil {
+ return errors.New("missing required field 'r' for txdata")
+ }
+ t.R = (*big.Int)(dec.R)
+ if dec.S == nil {
+ return errors.New("missing required field 's' for txdata")
+ }
+ t.S = (*big.Int)(dec.S)
+ if dec.Hash != nil {
+ t.Hash = dec.Hash
+ }
+ return nil
+}
diff --git a/core/types/log.go b/core/types/log.go
new file mode 100644
index 0000000..0b6184f
--- /dev/null
+++ b/core/types/log.go
@@ -0,0 +1,143 @@
+// 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 types
+
+import (
+ "io"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/rlp"
+)
+
+//go:generate gencodec -type Log -field-override logMarshaling -out gen_log_json.go
+
+// Log represents a contract log event. These events are generated by the LOG opcode and
+// stored/indexed by the node.
+type Log struct {
+ // Consensus fields:
+ // address of the contract that generated the event
+ Address common.Address `json:"address" gencodec:"required"`
+ // list of topics provided by the contract.
+ Topics []common.Hash `json:"topics" gencodec:"required"`
+ // supplied by the contract, usually ABI-encoded
+ Data []byte `json:"data" gencodec:"required"`
+
+ // Derived fields. These fields are filled in by the node
+ // but not secured by consensus.
+ // block in which the transaction was included
+ BlockNumber uint64 `json:"blockNumber"`
+ // hash of the transaction
+ TxHash common.Hash `json:"transactionHash" gencodec:"required"`
+ // index of the transaction in the block
+ TxIndex uint `json:"transactionIndex" gencodec:"required"`
+ // hash of the block in which the transaction was included
+ BlockHash common.Hash `json:"blockHash"`
+ // index of the log in the block
+ Index uint `json:"logIndex" gencodec:"required"`
+
+ // The Removed field is true if this log was reverted due to a chain reorganisation.
+ // You must pay attention to this field if you receive logs through a filter query.
+ Removed bool `json:"removed"`
+}
+
+type logMarshaling struct {
+ Data hexutil.Bytes
+ BlockNumber hexutil.Uint64
+ TxIndex hexutil.Uint
+ Index hexutil.Uint
+}
+
+type rlpLog struct {
+ Address common.Address
+ Topics []common.Hash
+ Data []byte
+}
+
+// rlpStorageLog is the storage encoding of a log.
+type rlpStorageLog rlpLog
+
+// legacyRlpStorageLog is the previous storage encoding of a log including some redundant fields.
+type legacyRlpStorageLog struct {
+ Address common.Address
+ Topics []common.Hash
+ Data []byte
+ BlockNumber uint64
+ TxHash common.Hash
+ TxIndex uint
+ BlockHash common.Hash
+ Index uint
+}
+
+// EncodeRLP implements rlp.Encoder.
+func (l *Log) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
+}
+
+// DecodeRLP implements rlp.Decoder.
+func (l *Log) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpLog
+ err := s.Decode(&dec)
+ if err == nil {
+ l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
+ }
+ return err
+}
+
+// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
+// a log including non-consensus fields.
+type LogForStorage Log
+
+// EncodeRLP implements rlp.Encoder.
+func (l *LogForStorage) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, rlpStorageLog{
+ Address: l.Address,
+ Topics: l.Topics,
+ Data: l.Data,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder.
+//
+// Note some redundant fields(e.g. block number, tx hash etc) will be assembled later.
+func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
+ blob, err := s.Raw()
+ if err != nil {
+ return err
+ }
+ var dec rlpStorageLog
+ err = rlp.DecodeBytes(blob, &dec)
+ if err == nil {
+ *l = LogForStorage{
+ Address: dec.Address,
+ Topics: dec.Topics,
+ Data: dec.Data,
+ }
+ } else {
+ // Try to decode log with previous definition.
+ var dec legacyRlpStorageLog
+ err = rlp.DecodeBytes(blob, &dec)
+ if err == nil {
+ *l = LogForStorage{
+ Address: dec.Address,
+ Topics: dec.Topics,
+ Data: dec.Data,
+ }
+ }
+ }
+ return err
+}
diff --git a/core/types/receipt.go b/core/types/receipt.go
new file mode 100644
index 0000000..46538e8
--- /dev/null
+++ b/core/types/receipt.go
@@ -0,0 +1,336 @@
+// 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 types
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "unsafe"
+
+ "github.com/ava-labs/coreth/params"
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/crypto"
+ "github.com/ava-labs/go-ethereum/rlp"
+)
+
+//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
+
+var (
+ receiptStatusFailedRLP = []byte{}
+ receiptStatusSuccessfulRLP = []byte{0x01}
+)
+
+const (
+ // ReceiptStatusFailed is the status code of a transaction if execution failed.
+ ReceiptStatusFailed = uint64(0)
+
+ // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
+ ReceiptStatusSuccessful = uint64(1)
+)
+
+// Receipt represents the results of a transaction.
+type Receipt struct {
+ // Consensus fields: These fields are defined by the Yellow Paper
+ PostState []byte `json:"root"`
+ Status uint64 `json:"status"`
+ CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
+ Bloom Bloom `json:"logsBloom" gencodec:"required"`
+ Logs []*Log `json:"logs" gencodec:"required"`
+
+ // Implementation fields: These fields are added by geth when processing a transaction.
+ // They are stored in the chain database.
+ TxHash common.Hash `json:"transactionHash" gencodec:"required"`
+ ContractAddress common.Address `json:"contractAddress"`
+ GasUsed uint64 `json:"gasUsed" gencodec:"required"`
+
+ // Inclusion information: These fields provide information about the inclusion of the
+ // transaction corresponding to this receipt.
+ BlockHash common.Hash `json:"blockHash,omitempty"`
+ BlockNumber *big.Int `json:"blockNumber,omitempty"`
+ TransactionIndex uint `json:"transactionIndex"`
+}
+
+type receiptMarshaling struct {
+ PostState hexutil.Bytes
+ Status hexutil.Uint64
+ CumulativeGasUsed hexutil.Uint64
+ GasUsed hexutil.Uint64
+ BlockNumber *hexutil.Big
+ TransactionIndex hexutil.Uint
+}
+
+// receiptRLP is the consensus encoding of a receipt.
+type receiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ Bloom Bloom
+ Logs []*Log
+}
+
+// storedReceiptRLP is the storage encoding of a receipt.
+type storedReceiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ Logs []*LogForStorage
+}
+
+// v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
+type v4StoredReceiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ TxHash common.Hash
+ ContractAddress common.Address
+ Logs []*LogForStorage
+ GasUsed uint64
+}
+
+// v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields.
+type v3StoredReceiptRLP struct {
+ PostStateOrStatus []byte
+ CumulativeGasUsed uint64
+ Bloom Bloom
+ TxHash common.Hash
+ ContractAddress common.Address
+ Logs []*LogForStorage
+ GasUsed uint64
+}
+
+// NewReceipt creates a barebone transaction receipt, copying the init fields.
+func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
+ r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed}
+ if failed {
+ r.Status = ReceiptStatusFailed
+ } else {
+ r.Status = ReceiptStatusSuccessful
+ }
+ return r
+}
+
+// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
+// into an RLP stream. If no post state is present, byzantium fork is assumed.
+func (r *Receipt) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
+}
+
+// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
+// from an RLP stream.
+func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
+ var dec receiptRLP
+ if err := s.Decode(&dec); err != nil {
+ return err
+ }
+ if err := r.setStatus(dec.PostStateOrStatus); err != nil {
+ return err
+ }
+ r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
+ return nil
+}
+
+func (r *Receipt) setStatus(postStateOrStatus []byte) error {
+ switch {
+ case bytes.Equal(postStateOrStatus, receiptStatusSuccessfulRLP):
+ r.Status = ReceiptStatusSuccessful
+ case bytes.Equal(postStateOrStatus, receiptStatusFailedRLP):
+ r.Status = ReceiptStatusFailed
+ case len(postStateOrStatus) == len(common.Hash{}):
+ r.PostState = postStateOrStatus
+ default:
+ return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
+ }
+ return nil
+}
+
+func (r *Receipt) statusEncoding() []byte {
+ if len(r.PostState) == 0 {
+ if r.Status == ReceiptStatusFailed {
+ return receiptStatusFailedRLP
+ }
+ return receiptStatusSuccessfulRLP
+ }
+ return r.PostState
+}
+
+// Size returns the approximate memory used by all internal contents. It is used
+// to approximate and limit the memory consumption of various caches.
+func (r *Receipt) Size() common.StorageSize {
+ size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
+
+ size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
+ for _, log := range r.Logs {
+ size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
+ }
+ return size
+}
+
+// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
+// entire content of a receipt, as opposed to only the consensus fields originally.
+type ReceiptForStorage Receipt
+
+// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
+// into an RLP stream.
+func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
+ enc := &storedReceiptRLP{
+ PostStateOrStatus: (*Receipt)(r).statusEncoding(),
+ CumulativeGasUsed: r.CumulativeGasUsed,
+ Logs: make([]*LogForStorage, len(r.Logs)),
+ }
+ for i, log := range r.Logs {
+ enc.Logs[i] = (*LogForStorage)(log)
+ }
+ return rlp.Encode(w, enc)
+}
+
+// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
+// fields of a receipt from an RLP stream.
+func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
+ // Retrieve the entire receipt blob as we need to try multiple decoders
+ blob, err := s.Raw()
+ if err != nil {
+ return err
+ }
+ // Try decoding from the newest format for future proofness, then the older one
+ // for old nodes that just upgraded. V4 was an intermediate unreleased format so
+ // we do need to decode it, but it's not common (try last).
+ if err := decodeStoredReceiptRLP(r, blob); err == nil {
+ return nil
+ }
+ if err := decodeV3StoredReceiptRLP(r, blob); err == nil {
+ return nil
+ }
+ return decodeV4StoredReceiptRLP(r, blob)
+}
+
+func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
+ var stored storedReceiptRLP
+ if err := rlp.DecodeBytes(blob, &stored); err != nil {
+ return err
+ }
+ if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
+ return err
+ }
+ r.CumulativeGasUsed = stored.CumulativeGasUsed
+ r.Logs = make([]*Log, len(stored.Logs))
+ for i, log := range stored.Logs {
+ r.Logs[i] = (*Log)(log)
+ }
+ r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
+
+ return nil
+}
+
+func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
+ var stored v4StoredReceiptRLP
+ if err := rlp.DecodeBytes(blob, &stored); err != nil {
+ return err
+ }
+ if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
+ return err
+ }
+ r.CumulativeGasUsed = stored.CumulativeGasUsed
+ r.TxHash = stored.TxHash
+ r.ContractAddress = stored.ContractAddress
+ r.GasUsed = stored.GasUsed
+ r.Logs = make([]*Log, len(stored.Logs))
+ for i, log := range stored.Logs {
+ r.Logs[i] = (*Log)(log)
+ }
+ r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
+
+ return nil
+}
+
+func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
+ var stored v3StoredReceiptRLP
+ if err := rlp.DecodeBytes(blob, &stored); err != nil {
+ return err
+ }
+ if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
+ return err
+ }
+ r.CumulativeGasUsed = stored.CumulativeGasUsed
+ r.Bloom = stored.Bloom
+ r.TxHash = stored.TxHash
+ r.ContractAddress = stored.ContractAddress
+ r.GasUsed = stored.GasUsed
+ r.Logs = make([]*Log, len(stored.Logs))
+ for i, log := range stored.Logs {
+ r.Logs[i] = (*Log)(log)
+ }
+ return nil
+}
+
+// Receipts is a wrapper around a Receipt array to implement DerivableList.
+type Receipts []*Receipt
+
+// 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
+}
+
+// DeriveFields fills the receipts with their computed fields based on consensus
+// data and contextual infos like containing block and transactions.
+func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
+ signer := MakeSigner(config, new(big.Int).SetUint64(number))
+
+ logIndex := uint(0)
+ if len(txs) != len(r) {
+ return errors.New("transaction and receipt count mismatch")
+ }
+ for i := 0; i < len(r); i++ {
+ // The transaction hash can be retrieved from the transaction itself
+ r[i].TxHash = txs[i].Hash()
+
+ // block location fields
+ r[i].BlockHash = hash
+ r[i].BlockNumber = new(big.Int).SetUint64(number)
+ r[i].TransactionIndex = uint(i)
+
+ // The contract address can be derived from the transaction itself
+ if txs[i].To() == nil {
+ // Deriving the signer is expensive, only do if it's actually needed
+ from, _ := Sender(signer, txs[i])
+ r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
+ }
+ // The used gas can be calculated based on previous r
+ if i == 0 {
+ r[i].GasUsed = r[i].CumulativeGasUsed
+ } else {
+ r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
+ }
+ // The derived log fields can simply be set from the block and transaction
+ for j := 0; j < len(r[i].Logs); j++ {
+ r[i].Logs[j].BlockNumber = number
+ r[i].Logs[j].BlockHash = hash
+ r[i].Logs[j].TxHash = r[i].TxHash
+ r[i].Logs[j].TxIndex = uint(i)
+ r[i].Logs[j].Index = logIndex
+ logIndex++
+ }
+ }
+ return nil
+}
diff --git a/core/types/transaction.go b/core/types/transaction.go
new file mode 100644
index 0000000..d9ada38
--- /dev/null
+++ b/core/types/transaction.go
@@ -0,0 +1,419 @@
+// 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 types
+
+import (
+ "container/heap"
+ "errors"
+ "io"
+ "math/big"
+ "sync/atomic"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/crypto"
+ "github.com/ava-labs/go-ethereum/rlp"
+)
+
+//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
+
+var (
+ ErrInvalidSig = errors.New("invalid transaction v, r, s values")
+)
+
+type Transaction struct {
+ data txdata
+ // caches
+ hash atomic.Value
+ size atomic.Value
+ from atomic.Value
+}
+
+type txdata struct {
+ AccountNonce uint64 `json:"nonce" gencodec:"required"`
+ Price *big.Int `json:"gasPrice" gencodec:"required"`
+ GasLimit uint64 `json:"gas" gencodec:"required"`
+ Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
+ Amount *big.Int `json:"value" gencodec:"required"`
+ Payload []byte `json:"input" gencodec:"required"`
+
+ // Signature values
+ V *big.Int `json:"v" gencodec:"required"`
+ R *big.Int `json:"r" gencodec:"required"`
+ S *big.Int `json:"s" gencodec:"required"`
+
+ // This is only used when marshaling to JSON.
+ Hash *common.Hash `json:"hash" rlp:"-"`
+}
+
+type txdataMarshaling struct {
+ AccountNonce hexutil.Uint64
+ Price *hexutil.Big
+ GasLimit hexutil.Uint64
+ Amount *hexutil.Big
+ Payload hexutil.Bytes
+ V *hexutil.Big
+ R *hexutil.Big
+ S *hexutil.Big
+}
+
+func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
+ return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
+}
+
+func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
+ return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
+}
+
+func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
+ if len(data) > 0 {
+ data = common.CopyBytes(data)
+ }
+ d := txdata{
+ AccountNonce: nonce,
+ Recipient: to,
+ Payload: data,
+ Amount: new(big.Int),
+ GasLimit: gasLimit,
+ Price: new(big.Int),
+ V: new(big.Int),
+ R: new(big.Int),
+ S: new(big.Int),
+ }
+ if amount != nil {
+ d.Amount.Set(amount)
+ }
+ if gasPrice != nil {
+ d.Price.Set(gasPrice)
+ }
+
+ return &Transaction{data: d}
+}
+
+// ChainId returns which chain id this transaction was signed for (if at all)
+func (tx *Transaction) ChainId() *big.Int {
+ return deriveChainId(tx.data.V)
+}
+
+// Protected returns whether the transaction is protected from replay protection.
+func (tx *Transaction) Protected() bool {
+ return isProtectedV(tx.data.V)
+}
+
+func isProtectedV(V *big.Int) bool {
+ if V.BitLen() <= 8 {
+ v := V.Uint64()
+ return v != 27 && v != 28
+ }
+ // anything not 27 or 28 is considered protected
+ return true
+}
+
+// EncodeRLP implements rlp.Encoder
+func (tx *Transaction) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, &tx.data)
+}
+
+// DecodeRLP implements rlp.Decoder
+func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
+ _, size, _ := s.Kind()
+ err := s.Decode(&tx.data)
+ if err == nil {
+ tx.size.Store(common.StorageSize(rlp.ListSize(size)))
+ }
+
+ return err
+}
+
+// MarshalJSON encodes the web3 RPC transaction format.
+func (tx *Transaction) MarshalJSON() ([]byte, error) {
+ hash := tx.Hash()
+ data := tx.data
+ data.Hash = &hash
+ return data.MarshalJSON()
+}
+
+// UnmarshalJSON decodes the web3 RPC transaction format.
+func (tx *Transaction) UnmarshalJSON(input []byte) error {
+ var dec txdata
+ if err := dec.UnmarshalJSON(input); err != nil {
+ return err
+ }
+
+ withSignature := dec.V.Sign() != 0 || dec.R.Sign() != 0 || dec.S.Sign() != 0
+ if withSignature {
+ var V byte
+ if isProtectedV(dec.V) {
+ chainID := deriveChainId(dec.V).Uint64()
+ V = byte(dec.V.Uint64() - 35 - 2*chainID)
+ } else {
+ V = byte(dec.V.Uint64() - 27)
+ }
+ if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
+ return ErrInvalidSig
+ }
+ }
+
+ *tx = Transaction{data: dec}
+ return nil
+}
+
+func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
+func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
+func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
+func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
+func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
+func (tx *Transaction) CheckNonce() bool { return true }
+
+// To returns the recipient address of the transaction.
+// It returns nil if the transaction is a contract creation.
+func (tx *Transaction) To() *common.Address {
+ if tx.data.Recipient == nil {
+ return nil
+ }
+ to := *tx.data.Recipient
+ return &to
+}
+
+// Hash hashes the RLP encoding of tx.
+// It uniquely identifies the transaction.
+func (tx *Transaction) Hash() common.Hash {
+ if hash := tx.hash.Load(); hash != nil {
+ return hash.(common.Hash)
+ }
+ v := rlpHash(tx)
+ tx.hash.Store(v)
+ return v
+}
+
+// Size returns the true RLP encoded storage size of the transaction, either by
+// encoding and returning it, or returning a previsouly cached value.
+func (tx *Transaction) Size() common.StorageSize {
+ if size := tx.size.Load(); size != nil {
+ return size.(common.StorageSize)
+ }
+ c := writeCounter(0)
+ rlp.Encode(&c, &tx.data)
+ tx.size.Store(common.StorageSize(c))
+ return common.StorageSize(c)
+}
+
+// AsMessage returns the transaction as a core.Message.
+//
+// AsMessage requires a signer to derive the sender.
+//
+// XXX Rename message to something less arbitrary?
+func (tx *Transaction) AsMessage(s Signer) (Message, error) {
+ msg := Message{
+ nonce: tx.data.AccountNonce,
+ gasLimit: tx.data.GasLimit,
+ gasPrice: new(big.Int).Set(tx.data.Price),
+ to: tx.data.Recipient,
+ amount: tx.data.Amount,
+ data: tx.data.Payload,
+ checkNonce: true,
+ }
+
+ var err error
+ msg.from, err = Sender(s, tx)
+ return msg, err
+}
+
+// WithSignature returns a new transaction with the given signature.
+// This signature needs to be in the [R || S || V] format where V is 0 or 1.
+func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
+ r, s, v, err := signer.SignatureValues(tx, sig)
+ if err != nil {
+ return nil, err
+ }
+ cpy := &Transaction{data: tx.data}
+ cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
+ return cpy, nil
+}
+
+// Cost returns amount + gasprice * gaslimit.
+func (tx *Transaction) Cost() *big.Int {
+ total := new(big.Int).Mul(tx.data.Price, new(big.Int).SetUint64(tx.data.GasLimit))
+ total.Add(total, tx.data.Amount)
+ return total
+}
+
+// RawSignatureValues returns the V, R, S signature values of the transaction.
+// The return values should not be modified by the caller.
+func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
+ return tx.data.V, tx.data.R, tx.data.S
+}
+
+// Transactions is a Transaction slice type for basic sorting.
+type Transactions []*Transaction
+
+// Len returns the length of s.
+func (s Transactions) Len() int { return len(s) }
+
+// Swap swaps the i'th and the j'th element in s.
+func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// GetRlp implements Rlpable and returns the i'th element of s in rlp.
+func (s Transactions) GetRlp(i int) []byte {
+ enc, _ := rlp.EncodeToBytes(s[i])
+ return enc
+}
+
+// TxDifference returns a new set which is the difference between a and b.
+func TxDifference(a, b Transactions) Transactions {
+ keep := make(Transactions, 0, len(a))
+
+ remove := make(map[common.Hash]struct{})
+ for _, tx := range b {
+ remove[tx.Hash()] = struct{}{}
+ }
+
+ for _, tx := range a {
+ if _, ok := remove[tx.Hash()]; !ok {
+ keep = append(keep, tx)
+ }
+ }
+
+ return keep
+}
+
+// TxByNonce implements the sort interface to allow sorting a list of transactions
+// by their nonces. This is usually only useful for sorting transactions from a
+// single account, otherwise a nonce comparison doesn't make much sense.
+type TxByNonce Transactions
+
+func (s TxByNonce) Len() int { return len(s) }
+func (s TxByNonce) Less(i, j int) bool { return s[i].data.AccountNonce < s[j].data.AccountNonce }
+func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// TxByPrice implements both the sort and the heap interface, making it useful
+// for all at once sorting as well as individually adding and removing elements.
+type TxByPrice Transactions
+
+func (s TxByPrice) Len() int { return len(s) }
+func (s TxByPrice) Less(i, j int) bool { return s[i].data.Price.Cmp(s[j].data.Price) > 0 }
+func (s TxByPrice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (s *TxByPrice) Push(x interface{}) {
+ *s = append(*s, x.(*Transaction))
+}
+
+func (s *TxByPrice) Pop() interface{} {
+ old := *s
+ n := len(old)
+ x := old[n-1]
+ *s = old[0 : n-1]
+ return x
+}
+
+// TransactionsByPriceAndNonce represents a set of transactions that can return
+// transactions in a profit-maximizing sorted order, while supporting removing
+// entire batches of transactions for non-executable accounts.
+type TransactionsByPriceAndNonce struct {
+ txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
+ heads TxByPrice // Next transaction for each unique account (price heap)
+ signer Signer // Signer for the set of transactions
+}
+
+// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve
+// price sorted transactions in a nonce-honouring way.
+//
+// Note, the input map is reowned so the caller should not interact any more with
+// if after providing it to the constructor.
+func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) *TransactionsByPriceAndNonce {
+ // Initialize a price based heap with the head transactions
+ heads := make(TxByPrice, 0, len(txs))
+ for from, accTxs := range txs {
+ heads = append(heads, accTxs[0])
+ // Ensure the sender address is from the signer
+ acc, _ := Sender(signer, accTxs[0])
+ txs[acc] = accTxs[1:]
+ if from != acc {
+ delete(txs, from)
+ }
+ }
+ heap.Init(&heads)
+
+ // Assemble and return the transaction set
+ return &TransactionsByPriceAndNonce{
+ txs: txs,
+ heads: heads,
+ signer: signer,
+ }
+}
+
+// Peek returns the next transaction by price.
+func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
+ if len(t.heads) == 0 {
+ return nil
+ }
+ return t.heads[0]
+}
+
+// Shift replaces the current best head with the next one from the same account.
+func (t *TransactionsByPriceAndNonce) Shift() {
+ acc, _ := Sender(t.signer, t.heads[0])
+ if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
+ t.heads[0], t.txs[acc] = txs[0], txs[1:]
+ heap.Fix(&t.heads, 0)
+ } else {
+ heap.Pop(&t.heads)
+ }
+}
+
+// Pop removes the best transaction, *not* replacing it with the next one from
+// the same account. This should be used when a transaction cannot be executed
+// and hence all subsequent ones should be discarded from the same account.
+func (t *TransactionsByPriceAndNonce) Pop() {
+ heap.Pop(&t.heads)
+}
+
+// Message is a fully derived transaction and implements core.Message
+//
+// NOTE: In a future PR this will be removed.
+type Message struct {
+ to *common.Address
+ from common.Address
+ nonce uint64
+ amount *big.Int
+ gasLimit uint64
+ gasPrice *big.Int
+ data []byte
+ checkNonce bool
+}
+
+func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool) Message {
+ return Message{
+ from: from,
+ to: to,
+ nonce: nonce,
+ amount: amount,
+ gasLimit: gasLimit,
+ gasPrice: gasPrice,
+ data: data,
+ checkNonce: checkNonce,
+ }
+}
+
+func (m Message) From() common.Address { return m.from }
+func (m Message) To() *common.Address { return m.to }
+func (m Message) GasPrice() *big.Int { return m.gasPrice }
+func (m Message) Value() *big.Int { return m.amount }
+func (m Message) Gas() uint64 { return m.gasLimit }
+func (m Message) Nonce() uint64 { return m.nonce }
+func (m Message) Data() []byte { return m.data }
+func (m Message) CheckNonce() bool { return m.checkNonce }
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
new file mode 100644
index 0000000..cb556eb
--- /dev/null
+++ b/core/types/transaction_signing.go
@@ -0,0 +1,260 @@
+// Copyright 2016 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 types
+
+import (
+ "crypto/ecdsa"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/ava-labs/coreth/params"
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/crypto"
+)
+
+var (
+ ErrInvalidChainId = errors.New("invalid chain id for signer")
+)
+
+// sigCache is used to cache the derived sender and contains
+// the signer used to derive it.
+type sigCache struct {
+ signer Signer
+ from common.Address
+}
+
+// MakeSigner returns a Signer based on the given chain config and block number.
+func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
+ var signer Signer
+ switch {
+ case config.IsEIP155(blockNumber):
+ signer = NewEIP155Signer(config.ChainID)
+ case config.IsHomestead(blockNumber):
+ signer = HomesteadSigner{}
+ default:
+ signer = FrontierSigner{}
+ }
+ return signer
+}
+
+// SignTx signs the transaction using the given signer and private key
+func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
+ h := s.Hash(tx)
+ sig, err := crypto.Sign(h[:], prv)
+ if err != nil {
+ return nil, err
+ }
+ return tx.WithSignature(s, sig)
+}
+
+// Sender returns the address derived from the signature (V, R, S) using secp256k1
+// elliptic curve and an error if it failed deriving or upon an incorrect
+// signature.
+//
+// Sender may cache the address, allowing it to be used regardless of
+// signing method. The cache is invalidated if the cached signer does
+// not match the signer used in the current call.
+func Sender(signer Signer, tx *Transaction) (common.Address, error) {
+ if sc := tx.from.Load(); sc != nil {
+ sigCache := sc.(sigCache)
+ // If the signer used to derive from in a previous
+ // call is not the same as used current, invalidate
+ // the cache.
+ if sigCache.signer.Equal(signer) {
+ return sigCache.from, nil
+ }
+ }
+
+ addr, err := signer.Sender(tx)
+ if err != nil {
+ return common.Address{}, err
+ }
+ tx.from.Store(sigCache{signer: signer, from: addr})
+ return addr, nil
+}
+
+// Signer encapsulates transaction signature handling. Note that this interface is not a
+// stable API and may change at any time to accommodate new protocol rules.
+type Signer interface {
+ // Sender returns the sender address of the transaction.
+ Sender(tx *Transaction) (common.Address, error)
+ // SignatureValues returns the raw R, S, V values corresponding to the
+ // given signature.
+ SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
+ // Hash returns the hash to be signed.
+ Hash(tx *Transaction) common.Hash
+ // Equal returns true if the given signer is the same as the receiver.
+ Equal(Signer) bool
+}
+
+// EIP155Transaction implements Signer using the EIP155 rules.
+type EIP155Signer struct {
+ chainId, chainIdMul *big.Int
+}
+
+func NewEIP155Signer(chainId *big.Int) EIP155Signer {
+ if chainId == nil {
+ chainId = new(big.Int)
+ }
+ return EIP155Signer{
+ chainId: chainId,
+ chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
+ }
+}
+
+func (s EIP155Signer) Equal(s2 Signer) bool {
+ eip155, ok := s2.(EIP155Signer)
+ return ok && eip155.chainId.Cmp(s.chainId) == 0
+}
+
+var big8 = big.NewInt(8)
+
+func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
+ if !tx.Protected() {
+ return HomesteadSigner{}.Sender(tx)
+ }
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return common.Address{}, ErrInvalidChainId
+ }
+ V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
+ V.Sub(V, big8)
+ return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
+}
+
+// SignatureValues returns signature values. This signature
+// needs to be in the [R || S || V] format where V is 0 or 1.
+func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
+ R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if s.chainId.Sign() != 0 {
+ V = big.NewInt(int64(sig[64] + 35))
+ V.Add(V, s.chainIdMul)
+ }
+ return R, S, V, nil
+}
+
+// Hash returns the hash to be signed by the sender.
+// It does not uniquely identify the transaction.
+func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
+ return rlpHash([]interface{}{
+ tx.data.AccountNonce,
+ tx.data.Price,
+ tx.data.GasLimit,
+ tx.data.Recipient,
+ tx.data.Amount,
+ tx.data.Payload,
+ s.chainId, uint(0), uint(0),
+ })
+}
+
+// HomesteadTransaction implements TransactionInterface using the
+// homestead rules.
+type HomesteadSigner struct{ FrontierSigner }
+
+func (s HomesteadSigner) Equal(s2 Signer) bool {
+ _, ok := s2.(HomesteadSigner)
+ return ok
+}
+
+// SignatureValues returns signature values. This signature
+// needs to be in the [R || S || V] format where V is 0 or 1.
+func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
+ return hs.FrontierSigner.SignatureValues(tx, sig)
+}
+
+func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
+ return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
+}
+
+type FrontierSigner struct{}
+
+func (s FrontierSigner) Equal(s2 Signer) bool {
+ _, ok := s2.(FrontierSigner)
+ return ok
+}
+
+// SignatureValues returns signature values. This signature
+// needs to be in the [R || S || V] format where V is 0 or 1.
+func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
+ if len(sig) != crypto.SignatureLength {
+ panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
+ }
+ r = new(big.Int).SetBytes(sig[:32])
+ s = new(big.Int).SetBytes(sig[32:64])
+ v = new(big.Int).SetBytes([]byte{sig[64] + 27})
+ return r, s, v, nil
+}
+
+// Hash returns the hash to be signed by the sender.
+// It does not uniquely identify the transaction.
+func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
+ return rlpHash([]interface{}{
+ tx.data.AccountNonce,
+ tx.data.Price,
+ tx.data.GasLimit,
+ tx.data.Recipient,
+ tx.data.Amount,
+ tx.data.Payload,
+ })
+}
+
+func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
+ return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
+}
+
+func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
+ if Vb.BitLen() > 8 {
+ return common.Address{}, ErrInvalidSig
+ }
+ V := byte(Vb.Uint64() - 27)
+ if !crypto.ValidateSignatureValues(V, R, S, homestead) {
+ return common.Address{}, ErrInvalidSig
+ }
+ // encode the signature in uncompressed format
+ r, s := R.Bytes(), S.Bytes()
+ sig := make([]byte, crypto.SignatureLength)
+ copy(sig[32-len(r):32], r)
+ copy(sig[64-len(s):64], s)
+ sig[64] = V
+ // recover the public key from the signature
+ pub, err := crypto.Ecrecover(sighash[:], sig)
+ if err != nil {
+ return common.Address{}, err
+ }
+ if len(pub) == 0 || pub[0] != 4 {
+ return common.Address{}, errors.New("invalid public key")
+ }
+ var addr common.Address
+ copy(addr[:], crypto.Keccak256(pub[1:])[12:])
+ return addr, nil
+}
+
+// deriveChainId derives the chain id from the given v parameter
+func deriveChainId(v *big.Int) *big.Int {
+ if v.BitLen() <= 64 {
+ v := v.Uint64()
+ if v == 27 || v == 28 {
+ return new(big.Int)
+ }
+ return new(big.Int).SetUint64((v - 35) / 2)
+ }
+ v = new(big.Int).Sub(v, big.NewInt(35))
+ return v.Div(v, big.NewInt(2))
+}