node.go 5.86 KB
Newer Older
1
// Copyright 2014 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// 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.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

17
package trie
obscuren's avatar
obscuren committed
18

Felix Lange's avatar
Felix Lange committed
19 20 21 22 23 24 25 26
import (
	"fmt"
	"io"
	"strings"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/rlp"
)
obscuren's avatar
obscuren committed
27 28 29

var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"}

Felix Lange's avatar
Felix Lange committed
30
type node interface {
obscuren's avatar
obscuren committed
31
	fstring(string) string
32
	cache() (hashNode, bool)
obscuren's avatar
obscuren committed
33 34
}

Felix Lange's avatar
Felix Lange committed
35
type (
36 37 38 39 40
	fullNode struct {
		Children [17]node // Actual trie node data to encode/decode (needs custom encoder)
		hash     hashNode // Cached hash of the node to prevent rehashing (may be nil)
		dirty    bool     // Cached flag whether the node's new or already stored
	}
Felix Lange's avatar
Felix Lange committed
41
	shortNode struct {
42 43 44 45
		Key   []byte
		Val   node
		hash  hashNode // Cached hash of the node to prevent rehashing (may be nil)
		dirty bool     // Cached flag whether the node's new or already stored
Felix Lange's avatar
Felix Lange committed
46 47 48 49
	}
	hashNode  []byte
	valueNode []byte
)
50

51 52 53 54 55 56 57 58 59 60 61
// EncodeRLP encodes a full node into the consensus RLP format.
func (n fullNode) EncodeRLP(w io.Writer) error {
	return rlp.Encode(w, n.Children)
}

// Cache accessors to retrieve precalculated values (avoid lengthy type switches).
func (n fullNode) cache() (hashNode, bool)  { return n.hash, n.dirty }
func (n shortNode) cache() (hashNode, bool) { return n.hash, n.dirty }
func (n hashNode) cache() (hashNode, bool)  { return nil, true }
func (n valueNode) cache() (hashNode, bool) { return nil, true }

Felix Lange's avatar
Felix Lange committed
62 63 64 65 66
// Pretty printing.
func (n fullNode) String() string  { return n.fstring("") }
func (n shortNode) String() string { return n.fstring("") }
func (n hashNode) String() string  { return n.fstring("") }
func (n valueNode) String() string { return n.fstring("") }
obscuren's avatar
obscuren committed
67

Felix Lange's avatar
Felix Lange committed
68
func (n fullNode) fstring(ind string) string {
obscuren's avatar
obscuren committed
69
	resp := fmt.Sprintf("[\n%s  ", ind)
70
	for i, node := range n.Children {
obscuren's avatar
obscuren committed
71 72 73 74 75 76 77 78
		if node == nil {
			resp += fmt.Sprintf("%s: <nil> ", indices[i])
		} else {
			resp += fmt.Sprintf("%s: %v", indices[i], node.fstring(ind+"  "))
		}
	}
	return resp + fmt.Sprintf("\n%s] ", ind)
}
Felix Lange's avatar
Felix Lange committed
79 80 81 82 83 84 85 86 87 88
func (n shortNode) fstring(ind string) string {
	return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+"  "))
}
func (n hashNode) fstring(ind string) string {
	return fmt.Sprintf("<%x> ", []byte(n))
}
func (n valueNode) fstring(ind string) string {
	return fmt.Sprintf("%x ", []byte(n))
}

89 90
func mustDecodeNode(hash, buf []byte) node {
	n, err := decodeNode(hash, buf)
Felix Lange's avatar
Felix Lange committed
91
	if err != nil {
92
		panic(fmt.Sprintf("node %x: %v", hash, err))
Felix Lange's avatar
Felix Lange committed
93 94 95 96 97
	}
	return n
}

// decodeNode parses the RLP encoding of a trie node.
98
func decodeNode(hash, buf []byte) (node, error) {
Felix Lange's avatar
Felix Lange committed
99 100 101 102 103 104 105 106 107
	if len(buf) == 0 {
		return nil, io.ErrUnexpectedEOF
	}
	elems, _, err := rlp.SplitList(buf)
	if err != nil {
		return nil, fmt.Errorf("decode error: %v", err)
	}
	switch c, _ := rlp.CountValues(elems); c {
	case 2:
108
		n, err := decodeShort(hash, buf, elems)
Felix Lange's avatar
Felix Lange committed
109 110
		return n, wrapError(err, "short")
	case 17:
111
		n, err := decodeFull(hash, buf, elems)
Felix Lange's avatar
Felix Lange committed
112 113 114 115 116 117
		return n, wrapError(err, "full")
	default:
		return nil, fmt.Errorf("invalid number of list elements: %v", c)
	}
}

118 119
func decodeShort(hash, buf, elems []byte) (node, error) {
	kbuf, rest, err := rlp.SplitString(elems)
Felix Lange's avatar
Felix Lange committed
120 121 122 123 124 125 126 127 128 129
	if err != nil {
		return nil, err
	}
	key := compactDecode(kbuf)
	if key[len(key)-1] == 16 {
		// value node
		val, _, err := rlp.SplitString(rest)
		if err != nil {
			return nil, fmt.Errorf("invalid value node: %v", err)
		}
130
		return shortNode{key, valueNode(val), hash, false}, nil
Felix Lange's avatar
Felix Lange committed
131 132 133 134 135
	}
	r, _, err := decodeRef(rest)
	if err != nil {
		return nil, wrapError(err, "val")
	}
136
	return shortNode{key, r, hash, false}, nil
Felix Lange's avatar
Felix Lange committed
137 138
}

139 140
func decodeFull(hash, buf, elems []byte) (fullNode, error) {
	n := fullNode{hash: hash}
Felix Lange's avatar
Felix Lange committed
141
	for i := 0; i < 16; i++ {
142
		cld, rest, err := decodeRef(elems)
Felix Lange's avatar
Felix Lange committed
143 144 145
		if err != nil {
			return n, wrapError(err, fmt.Sprintf("[%d]", i))
		}
146
		n.Children[i], elems = cld, rest
Felix Lange's avatar
Felix Lange committed
147
	}
148
	val, _, err := rlp.SplitString(elems)
Felix Lange's avatar
Felix Lange committed
149 150 151 152
	if err != nil {
		return n, err
	}
	if len(val) > 0 {
153
		n.Children[16] = valueNode(val)
Felix Lange's avatar
Felix Lange committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	}
	return n, nil
}

const hashLen = len(common.Hash{})

func decodeRef(buf []byte) (node, []byte, error) {
	kind, val, rest, err := rlp.Split(buf)
	if err != nil {
		return nil, buf, err
	}
	switch {
	case kind == rlp.List:
		// 'embedded' node reference. The encoding must be smaller
		// than a hash in order to be valid.
		if size := len(buf) - len(rest); size > hashLen {
			err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen)
			return nil, buf, err
		}
173
		n, err := decodeNode(nil, buf)
Felix Lange's avatar
Felix Lange committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
		return n, rest, err
	case kind == rlp.String && len(val) == 0:
		// empty node
		return nil, rest, nil
	case kind == rlp.String && len(val) == 32:
		return hashNode(val), rest, nil
	default:
		return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val))
	}
}

// wraps a decoding error with information about the path to the
// invalid child node (for debugging encoding issues).
type decodeError struct {
	what  error
	stack []string
}

func wrapError(err error, ctx string) error {
	if err == nil {
		return nil
	}
	if decErr, ok := err.(*decodeError); ok {
		decErr.stack = append(decErr.stack, ctx)
		return decErr
	}
	return &decodeError{err, []string{ctx}}
}
obscuren's avatar
obscuren committed
202

Felix Lange's avatar
Felix Lange committed
203 204
func (err *decodeError) Error() string {
	return fmt.Sprintf("%v (decode path: %s)", err.what, strings.Join(err.stack, "<-"))
obscuren's avatar
obscuren committed
205
}