github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/common/rlp.go (about) 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 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 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 // GNU Lesser General Public License for more details. 13 // 14 // 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 common 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/big" 23 "reflect" 24 ) 25 26 type RlpEncode interface { 27 RlpEncode() []byte 28 } 29 30 type RlpEncodeDecode interface { 31 RlpEncode 32 RlpValue() []interface{} 33 } 34 35 type RlpEncodable interface { 36 RlpData() interface{} 37 } 38 39 func Rlp(encoder RlpEncode) []byte { 40 return encoder.RlpEncode() 41 } 42 43 type RlpEncoder struct { 44 rlpData []byte 45 } 46 47 func NewRlpEncoder() *RlpEncoder { 48 encoder := &RlpEncoder{} 49 50 return encoder 51 } 52 func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { 53 return Encode(rlpData) 54 } 55 56 const ( 57 RlpEmptyList = 0x80 58 RlpEmptyStr = 0x40 59 ) 60 61 const rlpEof = -1 62 63 func Char(c []byte) int { 64 if len(c) > 0 { 65 return int(c[0]) 66 } 67 68 return rlpEof 69 } 70 71 func DecodeWithReader(reader *bytes.Buffer) interface{} { 72 var slice []interface{} 73 74 // Read the next byte 75 char := Char(reader.Next(1)) 76 switch { 77 case char <= 0x7f: 78 return char 79 80 case char <= 0xb7: 81 return reader.Next(int(char - 0x80)) 82 83 case char <= 0xbf: 84 length := ReadVarInt(reader.Next(int(char - 0xb7))) 85 86 return reader.Next(int(length)) 87 88 case char <= 0xf7: 89 length := int(char - 0xc0) 90 for i := 0; i < length; i++ { 91 obj := DecodeWithReader(reader) 92 slice = append(slice, obj) 93 } 94 95 return slice 96 case char <= 0xff: 97 length := ReadVarInt(reader.Next(int(char - 0xf7))) 98 for i := uint64(0); i < length; i++ { 99 obj := DecodeWithReader(reader) 100 slice = append(slice, obj) 101 } 102 103 return slice 104 default: 105 panic(fmt.Sprintf("byte not supported: %q", char)) 106 } 107 108 return slice 109 } 110 111 var ( 112 directRlp = big.NewInt(0x7f) 113 numberRlp = big.NewInt(0xb7) 114 zeroRlp = big.NewInt(0x0) 115 ) 116 117 func intlen(i int64) (length int) { 118 for i > 0 { 119 i = i >> 8 120 length++ 121 } 122 return 123 } 124 125 func Encode(object interface{}) []byte { 126 var buff bytes.Buffer 127 128 if object != nil { 129 switch t := object.(type) { 130 case *Value: 131 buff.Write(Encode(t.Val)) 132 case RlpEncodable: 133 buff.Write(Encode(t.RlpData())) 134 // Code dup :-/ 135 case int: 136 buff.Write(Encode(big.NewInt(int64(t)))) 137 case uint: 138 buff.Write(Encode(big.NewInt(int64(t)))) 139 case int8: 140 buff.Write(Encode(big.NewInt(int64(t)))) 141 case int16: 142 buff.Write(Encode(big.NewInt(int64(t)))) 143 case int32: 144 buff.Write(Encode(big.NewInt(int64(t)))) 145 case int64: 146 buff.Write(Encode(big.NewInt(t))) 147 case uint16: 148 buff.Write(Encode(big.NewInt(int64(t)))) 149 case uint32: 150 buff.Write(Encode(big.NewInt(int64(t)))) 151 case uint64: 152 buff.Write(Encode(big.NewInt(int64(t)))) 153 case byte: 154 buff.Write(Encode(big.NewInt(int64(t)))) 155 case *big.Int: 156 // Not sure how this is possible while we check for nil 157 if t == nil { 158 buff.WriteByte(0xc0) 159 } else { 160 buff.Write(Encode(t.Bytes())) 161 } 162 case Bytes: 163 buff.Write(Encode([]byte(t))) 164 case []byte: 165 if len(t) == 1 && t[0] <= 0x7f { 166 buff.Write(t) 167 } else if len(t) < 56 { 168 buff.WriteByte(byte(len(t) + 0x80)) 169 buff.Write(t) 170 } else { 171 b := big.NewInt(int64(len(t))) 172 buff.WriteByte(byte(len(b.Bytes()) + 0xb7)) 173 buff.Write(b.Bytes()) 174 buff.Write(t) 175 } 176 case string: 177 buff.Write(Encode([]byte(t))) 178 case []interface{}: 179 // Inline function for writing the slice header 180 WriteSliceHeader := func(length int) { 181 if length < 56 { 182 buff.WriteByte(byte(length + 0xc0)) 183 } else { 184 b := big.NewInt(int64(length)) 185 buff.WriteByte(byte(len(b.Bytes()) + 0xf7)) 186 buff.Write(b.Bytes()) 187 } 188 } 189 190 var b bytes.Buffer 191 for _, val := range t { 192 b.Write(Encode(val)) 193 } 194 WriteSliceHeader(len(b.Bytes())) 195 buff.Write(b.Bytes()) 196 default: 197 // This is how it should have been from the start 198 // needs refactoring (@fjl) 199 v := reflect.ValueOf(t) 200 switch v.Kind() { 201 case reflect.Slice: 202 var b bytes.Buffer 203 for i := 0; i < v.Len(); i++ { 204 b.Write(Encode(v.Index(i).Interface())) 205 } 206 207 blen := b.Len() 208 if blen < 56 { 209 buff.WriteByte(byte(blen) + 0xc0) 210 } else { 211 ilen := byte(intlen(int64(blen))) 212 buff.WriteByte(ilen + 0xf7) 213 t := make([]byte, ilen) 214 for i := byte(0); i < ilen; i++ { 215 t[ilen-i-1] = byte(blen >> (i * 8)) 216 } 217 buff.Write(t) 218 } 219 buff.ReadFrom(&b) 220 } 221 } 222 } else { 223 // Empty list for nil 224 buff.WriteByte(0xc0) 225 } 226 227 return buff.Bytes() 228 } 229 230 // TODO Use a bytes.Buffer instead of a raw byte slice. 231 // Cleaner code, and use draining instead of seeking the next bytes to read 232 func Decode(data []byte, pos uint64) (interface{}, uint64) { 233 var slice []interface{} 234 char := int(data[pos]) 235 switch { 236 case char <= 0x7f: 237 return data[pos], pos + 1 238 239 case char <= 0xb7: 240 b := uint64(data[pos]) - 0x80 241 242 return data[pos+1 : pos+1+b], pos + 1 + b 243 244 case char <= 0xbf: 245 b := uint64(data[pos]) - 0xb7 246 247 b2 := ReadVarInt(data[pos+1 : pos+1+b]) 248 249 return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 250 251 case char <= 0xf7: 252 b := uint64(data[pos]) - 0xc0 253 prevPos := pos 254 pos++ 255 for i := uint64(0); i < b; { 256 var obj interface{} 257 258 // Get the next item in the data list and append it 259 obj, prevPos = Decode(data, pos) 260 slice = append(slice, obj) 261 262 // Increment i by the amount bytes read in the previous 263 // read 264 i += (prevPos - pos) 265 pos = prevPos 266 } 267 return slice, pos 268 269 case char <= 0xff: 270 l := uint64(data[pos]) - 0xf7 271 b := ReadVarInt(data[pos+1 : pos+1+l]) 272 273 pos = pos + l + 1 274 275 prevPos := b 276 for i := uint64(0); i < uint64(b); { 277 var obj interface{} 278 279 obj, prevPos = Decode(data, pos) 280 slice = append(slice, obj) 281 282 i += (prevPos - pos) 283 pos = prevPos 284 } 285 return slice, pos 286 287 default: 288 panic(fmt.Sprintf("byte not supported: %q", char)) 289 } 290 291 return slice, 0 292 }