func (b *EthBlock) Copy() node.Node {
	panic("dont use this yet")
}
Copy will go away. It is here to comply with the Node interface.
package ipldeth
import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	cid "github.com/ipfs/go-cid"
	node "github.com/ipfs/go-ipld-format"
	"github.com/ethereum/go-ethereum/common"
	types "github.com/ethereum/go-ethereum/core/types"
	rlp "github.com/ethereum/go-ethereum/rlp"
)
type EthBlock struct {
	*types.Header
	cid     *cid.Cid
	rawdata []byte
}
var _ node.Node = (*EthBlock)(nil)
func FromBlockRLP(r io.Reader) (*EthBlock, []*EthTx, []*EthTxTrie, error) {
	rawdata, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, nil, nil, err
	}
	var decodedBlock types.Block
	err = rlp.Decode(bytes.NewBuffer(rawdata), &decodedBlock)
	if err != nil {
		if err.Error()[:41] != "rlp: expected input list for types.Header" {
			return nil, nil, nil, err
		}
		var decodedHeader types.Header
		err := rlp.Decode(bytes.NewBuffer(rawdata), &decodedHeader)
		if err != nil {
			return nil, nil, nil, err
		}
		return &EthBlock{
			Header:  &decodedHeader,
			cid:     rawdataToCid(MEthBlock, rawdata),
			rawdata: rawdata,
		}, nil, nil, nil
	}
	headerRawData := getRLP(decodedBlock.Header())
	ethBlock := &EthBlock{
		Header:  decodedBlock.Header(),
		cid:     rawdataToCid(MEthBlock, headerRawData),
		rawdata: headerRawData,
	}
	ethTxNodes, ethTxTrieNodes, err := processTransactions(decodedBlock.Transactions(),
		decodedBlock.Header().TxHash[:])
	if err != nil {
		return nil, nil, nil, err
	}
	return ethBlock, ethTxNodes, ethTxTrieNodes, nil
}
func FromBlockJSON(r io.Reader) (*EthBlock, []*EthTx, []*EthTxTrie, error) {
	var obj objJSONBlock
	dec := json.NewDecoder(r)
	err := dec.Decode(&obj)
	if err != nil {
		return nil, nil, nil, err
	}
	headerRawData := getRLP(obj.Result.Header)
	ethBlock := &EthBlock{
		Header:  &obj.Result.Header,
		cid:     rawdataToCid(MEthBlock, headerRawData),
		rawdata: headerRawData,
	}
	ethTxNodes, ethTxTrieNodes, err := processTransactions(obj.Result.Transactions,
		obj.Result.Header.TxHash[:])
	if err != nil {
		return nil, nil, nil, err
	}
	return ethBlock, ethTxNodes, ethTxTrieNodes, nil
}
func processTransactions(txs []*types.Transaction, expectedTxRoot []byte) ([]*EthTx, []*EthTxTrie, error) {
	var ethTxNodes []*EthTx
	transactionTrie := newTxTrie()
	for idx, tx := range txs {
		ethTx := NewTx(tx)  
		ethTxNodes = append(ethTxNodes, ethTx)
		transactionTrie.add(idx, ethTx.RawData())
	}
	if !bytes.Equal(transactionTrie.rootHash(), expectedTxRoot) {
		return nil, nil, fmt.Errorf("wrong transaction hash computed")
	}
	ethTxTrieNodes := transactionTrie.getNodes()
	return ethTxNodes, ethTxTrieNodes, nil
}
func DecodeEthBlock(c *cid.Cid, b []byte) (*EthBlock, error) {
	var h types.Header
	err := rlp.Decode(bytes.NewReader(b), &h)
	if err != nil {
		return nil, err
	}
	return &EthBlock{
		Header:  &h,
		cid:     c,
		rawdata: b,
	}, nil
}
func (b *EthBlock) RawData() []byte {
	return b.rawdata
}
func (b *EthBlock) Cid() *cid.Cid {
	return b.cid
}
func (b *EthBlock) String() string {
	return fmt.Sprintf("<EthBlock %s>", b.cid)
}
func (b *EthBlock) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"type": "eth-block",
	}
}
func (b *EthBlock) Resolve(p []string) (interface{}, []string, error) {
	if len(p) == 0 {
		return b, nil, nil
	}
	first, rest := p[0], p[1:]
	switch first {
	case "parent":
		return &node.Link{Cid: commonHashToCid(MEthBlock, b.ParentHash)}, rest, nil
	case "receipts":
		return &node.Link{Cid: commonHashToCid(MEthTxReceiptTrie, b.ReceiptHash)}, rest, nil
	case "root":
		return &node.Link{Cid: commonHashToCid(MEthStateTrie, b.Root)}, rest, nil
	case "tx":
		return &node.Link{Cid: commonHashToCid(MEthTxTrie, b.TxHash)}, rest, nil
	case "uncles":
		return &node.Link{Cid: commonHashToCid(MEthBlockList, b.UncleHash)}, rest, nil
	}
	if len(p) != 1 {
		return nil, nil, fmt.Errorf("unexpected path elements past %s", first)
	}
	switch first {
	case "bloom":
		return b.Bloom, nil, nil
	case "coinbase":
		return b.Coinbase, nil, nil
	case "difficulty":
		return b.Difficulty, nil, nil
	case "extra":
		return fmt.Sprintf("0x%x", b.Extra), nil, nil
	case "gaslimit":
		return b.GasLimit, nil, nil
	case "gasused":
		return b.GasUsed, nil, nil
	case "mixdigest":
		return b.MixDigest, nil, nil
	case "nonce":
		return b.Nonce, nil, nil
	case "number":
		return b.Number, nil, nil
	case "time":
		return b.Time, nil, nil
	default:
		return nil, nil, fmt.Errorf("no such link")
	}
}
func (b *EthBlock) Tree(p string, depth int) []string {
	if p != "" || depth == 0 {
		return nil
	}
	return []string{
		"time",
		"bloom",
		"coinbase",
		"difficulty",
		"extra",
		"gaslimit",
		"gasused",
		"mixdigest",
		"nonce",
		"number",
		"parent",
		"receipts",
		"root",
		"tx",
		"uncles",
	}
}
func (b *EthBlock) ResolveLink(p []string) (*node.Link, []string, error) {
	obj, rest, err := b.Resolve(p)
	if err != nil {
		return nil, nil, err
	}
	if lnk, ok := obj.(*node.Link); ok {
		return lnk, rest, nil
	}
	return nil, nil, fmt.Errorf("resolved item was not a link")
}