github.com/ledgerwatch/erigon-lib@v1.0.0/commitment/commitment.go (about) 1 package commitment 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "hash" 8 "math/bits" 9 "strings" 10 11 "golang.org/x/crypto/sha3" 12 13 "github.com/ledgerwatch/erigon-lib/common/length" 14 ) 15 16 // Trie represents commitment variant. 17 type Trie interface { 18 // RootHash produces root hash of the trie 19 RootHash() (hash []byte, err error) 20 21 // Variant returns commitment trie variant 22 Variant() TrieVariant 23 24 // Reset Drops everything from the trie 25 Reset() 26 27 ReviewKeys(pk, hk [][]byte) (rootHash []byte, branchNodeUpdates map[string]BranchData, err error) 28 29 ProcessUpdates(pk, hk [][]byte, updates []Update) (rootHash []byte, branchNodeUpdates map[string]BranchData, err error) 30 31 ResetFns( 32 branchFn func(prefix []byte) ([]byte, error), 33 accountFn func(plainKey []byte, cell *Cell) error, 34 storageFn func(plainKey []byte, cell *Cell) error, 35 ) 36 37 // Makes trie more verbose 38 SetTrace(bool) 39 } 40 41 type TrieVariant string 42 43 const ( 44 // VariantHexPatriciaTrie used as default commitment approach 45 VariantHexPatriciaTrie TrieVariant = "hex-patricia-hashed" 46 // VariantBinPatriciaTrie - Experimental mode with binary key representation 47 VariantBinPatriciaTrie TrieVariant = "bin-patricia-hashed" 48 ) 49 50 func InitializeTrie(tv TrieVariant) Trie { 51 switch tv { 52 case VariantBinPatriciaTrie: 53 return NewBinPatriciaHashed(length.Addr, nil, nil, nil) 54 case VariantHexPatriciaTrie: 55 fallthrough 56 default: 57 return NewHexPatriciaHashed(length.Addr, nil, nil, nil) 58 } 59 } 60 61 type PartFlags uint8 62 63 const ( 64 HashedKeyPart PartFlags = 1 65 AccountPlainPart PartFlags = 2 66 StoragePlainPart PartFlags = 4 67 HashPart PartFlags = 8 68 ) 69 70 type BranchData []byte 71 72 func (branchData BranchData) String() string { 73 touchMap := binary.BigEndian.Uint16(branchData[0:]) 74 afterMap := binary.BigEndian.Uint16(branchData[2:]) 75 pos := 4 76 var sb strings.Builder 77 var cell Cell 78 fmt.Fprintf(&sb, "touchMap %016b, afterMap %016b\n", touchMap, afterMap) 79 for bitset, j := touchMap, 0; bitset != 0; j++ { 80 bit := bitset & -bitset 81 nibble := bits.TrailingZeros16(bit) 82 fmt.Fprintf(&sb, " %x => ", nibble) 83 if afterMap&bit == 0 { 84 sb.WriteString("{DELETED}\n") 85 } else { 86 fieldBits := PartFlags(branchData[pos]) 87 pos++ 88 var err error 89 if pos, err = cell.fillFromFields(branchData, pos, fieldBits); err != nil { 90 // This is used for test output, so ok to panic 91 panic(err) 92 } 93 sb.WriteString("{") 94 var comma string 95 if cell.downHashedLen > 0 { 96 fmt.Fprintf(&sb, "hashedKey=[%x]", cell.downHashedKey[:cell.downHashedLen]) 97 comma = "," 98 } 99 if cell.apl > 0 { 100 fmt.Fprintf(&sb, "%saccountPlainKey=[%x]", comma, cell.apk[:cell.apl]) 101 comma = "," 102 } 103 if cell.spl > 0 { 104 fmt.Fprintf(&sb, "%sstoragePlainKey=[%x]", comma, cell.spk[:cell.spl]) 105 comma = "," 106 } 107 if cell.hl > 0 { 108 fmt.Fprintf(&sb, "%shash=[%x]", comma, cell.h[:cell.hl]) 109 } 110 sb.WriteString("}\n") 111 } 112 bitset ^= bit 113 } 114 return sb.String() 115 } 116 117 func EncodeBranch(bitmap, touchMap, afterMap uint16, retriveCell func(nibble int, skip bool) (*Cell, error)) (branchData BranchData, lastNibble int, err error) { 118 branchData = make(BranchData, 0, 32) 119 var bitmapBuf [binary.MaxVarintLen64]byte 120 121 binary.BigEndian.PutUint16(bitmapBuf[0:], touchMap) 122 binary.BigEndian.PutUint16(bitmapBuf[2:], afterMap) 123 124 branchData = append(branchData, bitmapBuf[:4]...) 125 126 for bitset, j := afterMap, 0; bitset != 0; j++ { 127 bit := bitset & -bitset 128 nibble := bits.TrailingZeros16(bit) 129 for i := lastNibble; i < nibble; i++ { 130 if _, err := retriveCell(i, true /* skip */); err != nil { 131 return nil, 0, err 132 } // only writes 0x80 into hasher 133 } 134 lastNibble = nibble + 1 135 136 cell, err := retriveCell(nibble, false) 137 if err != nil { 138 return nil, 0, err 139 } 140 141 if bitmap&bit != 0 { 142 var fieldBits PartFlags 143 if cell.extLen > 0 && cell.spl == 0 { 144 fieldBits |= HashedKeyPart 145 } 146 if cell.apl > 0 { 147 fieldBits |= AccountPlainPart 148 } 149 if cell.spl > 0 { 150 fieldBits |= StoragePlainPart 151 } 152 if cell.hl > 0 { 153 fieldBits |= HashPart 154 } 155 branchData = append(branchData, byte(fieldBits)) 156 if cell.extLen > 0 && cell.spl == 0 { 157 n := binary.PutUvarint(bitmapBuf[:], uint64(cell.extLen)) 158 branchData = append(branchData, bitmapBuf[:n]...) 159 branchData = append(branchData, cell.extension[:cell.extLen]...) 160 } 161 if cell.apl > 0 { 162 n := binary.PutUvarint(bitmapBuf[:], uint64(cell.apl)) 163 branchData = append(branchData, bitmapBuf[:n]...) 164 branchData = append(branchData, cell.apk[:cell.apl]...) 165 } 166 if cell.spl > 0 { 167 n := binary.PutUvarint(bitmapBuf[:], uint64(cell.spl)) 168 branchData = append(branchData, bitmapBuf[:n]...) 169 branchData = append(branchData, cell.spk[:cell.spl]...) 170 } 171 if cell.hl > 0 { 172 n := binary.PutUvarint(bitmapBuf[:], uint64(cell.hl)) 173 branchData = append(branchData, bitmapBuf[:n]...) 174 branchData = append(branchData, cell.h[:cell.hl]...) 175 } 176 } 177 bitset ^= bit 178 } 179 return branchData, lastNibble, nil 180 } 181 182 // ExtractPlainKeys parses branchData and extract the plain keys for accounts and storage in the same order 183 // they appear witjin the branchData 184 func (branchData BranchData) ExtractPlainKeys() (accountPlainKeys [][]byte, storagePlainKeys [][]byte, err error) { 185 touchMap := binary.BigEndian.Uint16(branchData[0:]) 186 afterMap := binary.BigEndian.Uint16(branchData[2:]) 187 pos := 4 188 for bitset, j := touchMap&afterMap, 0; bitset != 0; j++ { 189 bit := bitset & -bitset 190 fieldBits := PartFlags(branchData[pos]) 191 pos++ 192 if fieldBits&HashedKeyPart != 0 { 193 l, n := binary.Uvarint(branchData[pos:]) 194 if n == 0 { 195 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for hashedKey len") 196 } else if n < 0 { 197 return nil, nil, fmt.Errorf("extractPlainKeys value overflow for hashedKey len") 198 } 199 pos += n 200 if len(branchData) < pos+int(l) { 201 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for hashedKey") 202 } 203 if l > 0 { 204 pos += int(l) 205 } 206 } 207 if fieldBits&AccountPlainPart != 0 { 208 l, n := binary.Uvarint(branchData[pos:]) 209 if n == 0 { 210 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for accountPlainKey len") 211 } else if n < 0 { 212 return nil, nil, fmt.Errorf("extractPlainKeys value overflow for accountPlainKey len") 213 } 214 pos += n 215 if len(branchData) < pos+int(l) { 216 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for accountPlainKey") 217 } 218 accountPlainKeys = append(accountPlainKeys, branchData[pos:pos+int(l)]) 219 if l > 0 { 220 pos += int(l) 221 } 222 } 223 if fieldBits&StoragePlainPart != 0 { 224 l, n := binary.Uvarint(branchData[pos:]) 225 if n == 0 { 226 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for storagePlainKey len") 227 } else if n < 0 { 228 return nil, nil, fmt.Errorf("extractPlainKeys value overflow for storagePlainKey len") 229 } 230 pos += n 231 if len(branchData) < pos+int(l) { 232 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for storagePlainKey") 233 } 234 storagePlainKeys = append(storagePlainKeys, branchData[pos:pos+int(l)]) 235 if l > 0 { 236 pos += int(l) 237 } 238 } 239 if fieldBits&HashPart != 0 { 240 l, n := binary.Uvarint(branchData[pos:]) 241 if n == 0 { 242 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for hash len") 243 } else if n < 0 { 244 return nil, nil, fmt.Errorf("extractPlainKeys value overflow for hash len") 245 } 246 pos += n 247 if len(branchData) < pos+int(l) { 248 return nil, nil, fmt.Errorf("extractPlainKeys buffer too small for hash") 249 } 250 if l > 0 { 251 pos += int(l) 252 } 253 } 254 bitset ^= bit 255 } 256 return 257 } 258 259 func (branchData BranchData) ReplacePlainKeys(accountPlainKeys [][]byte, storagePlainKeys [][]byte, newData []byte) (BranchData, error) { 260 var numBuf [binary.MaxVarintLen64]byte 261 touchMap := binary.BigEndian.Uint16(branchData[0:]) 262 afterMap := binary.BigEndian.Uint16(branchData[2:]) 263 pos := 4 264 newData = append(newData, branchData[:4]...) 265 var accountI, storageI int 266 for bitset, j := touchMap&afterMap, 0; bitset != 0; j++ { 267 bit := bitset & -bitset 268 fieldBits := PartFlags(branchData[pos]) 269 newData = append(newData, byte(fieldBits)) 270 pos++ 271 if fieldBits&HashedKeyPart != 0 { 272 l, n := binary.Uvarint(branchData[pos:]) 273 if n == 0 { 274 return nil, fmt.Errorf("replacePlainKeys buffer too small for hashedKey len") 275 } else if n < 0 { 276 return nil, fmt.Errorf("replacePlainKeys value overflow for hashedKey len") 277 } 278 newData = append(newData, branchData[pos:pos+n]...) 279 pos += n 280 if len(branchData) < pos+int(l) { 281 return nil, fmt.Errorf("replacePlainKeys buffer too small for hashedKey") 282 } 283 if l > 0 { 284 newData = append(newData, branchData[pos:pos+int(l)]...) 285 pos += int(l) 286 } 287 } 288 if fieldBits&AccountPlainPart != 0 { 289 l, n := binary.Uvarint(branchData[pos:]) 290 if n == 0 { 291 return nil, fmt.Errorf("replacePlainKeys buffer too small for accountPlainKey len") 292 } else if n < 0 { 293 return nil, fmt.Errorf("replacePlainKeys value overflow for accountPlainKey len") 294 } 295 pos += n 296 if len(branchData) < pos+int(l) { 297 return nil, fmt.Errorf("replacePlainKeys buffer too small for accountPlainKey") 298 } 299 if l > 0 { 300 pos += int(l) 301 } 302 n = binary.PutUvarint(numBuf[:], uint64(len(accountPlainKeys[accountI]))) 303 newData = append(newData, numBuf[:n]...) 304 newData = append(newData, accountPlainKeys[accountI]...) 305 accountI++ 306 } 307 if fieldBits&StoragePlainPart != 0 { 308 l, n := binary.Uvarint(branchData[pos:]) 309 if n == 0 { 310 return nil, fmt.Errorf("replacePlainKeys buffer too small for storagePlainKey len") 311 } else if n < 0 { 312 return nil, fmt.Errorf("replacePlainKeys value overflow for storagePlainKey len") 313 } 314 pos += n 315 if len(branchData) < pos+int(l) { 316 return nil, fmt.Errorf("replacePlainKeys buffer too small for storagePlainKey") 317 } 318 if l > 0 { 319 pos += int(l) 320 } 321 n = binary.PutUvarint(numBuf[:], uint64(len(storagePlainKeys[storageI]))) 322 newData = append(newData, numBuf[:n]...) 323 newData = append(newData, storagePlainKeys[storageI]...) 324 storageI++ 325 } 326 if fieldBits&HashPart != 0 { 327 l, n := binary.Uvarint(branchData[pos:]) 328 if n == 0 { 329 return nil, fmt.Errorf("replacePlainKeys buffer too small for hash len") 330 } else if n < 0 { 331 return nil, fmt.Errorf("replacePlainKeys value overflow for hash len") 332 } 333 newData = append(newData, branchData[pos:pos+n]...) 334 pos += n 335 if len(branchData) < pos+int(l) { 336 return nil, fmt.Errorf("replacePlainKeys buffer too small for hash") 337 } 338 if l > 0 { 339 newData = append(newData, branchData[pos:pos+int(l)]...) 340 pos += int(l) 341 } 342 } 343 bitset ^= bit 344 } 345 return newData, nil 346 } 347 348 // IsComplete determines whether given branch data is complete, meaning that all information about all the children is present 349 // Each of 16 children of a branch node have two attributes 350 // touch - whether this child has been modified or deleted in this branchData (corresponding bit in touchMap is set) 351 // after - whether after this branchData application, the child is present in the tree or not (corresponding bit in afterMap is set) 352 func (branchData BranchData) IsComplete() bool { 353 touchMap := binary.BigEndian.Uint16(branchData[0:]) 354 afterMap := binary.BigEndian.Uint16(branchData[2:]) 355 return ^touchMap&afterMap == 0 356 } 357 358 // MergeHexBranches combines two branchData, number 2 coming after (and potentially shadowing) number 1 359 func (branchData BranchData) MergeHexBranches(branchData2 BranchData, newData []byte) (BranchData, error) { 360 if branchData2 == nil { 361 return branchData, nil 362 } 363 if branchData == nil { 364 return branchData2, nil 365 } 366 367 touchMap1 := binary.BigEndian.Uint16(branchData[0:]) 368 afterMap1 := binary.BigEndian.Uint16(branchData[2:]) 369 bitmap1 := touchMap1 & afterMap1 370 pos1 := 4 371 touchMap2 := binary.BigEndian.Uint16(branchData2[0:]) 372 afterMap2 := binary.BigEndian.Uint16(branchData2[2:]) 373 bitmap2 := touchMap2 & afterMap2 374 pos2 := 4 375 var bitmapBuf [4]byte 376 binary.BigEndian.PutUint16(bitmapBuf[0:], touchMap1|touchMap2) 377 binary.BigEndian.PutUint16(bitmapBuf[2:], afterMap2) 378 newData = append(newData, bitmapBuf[:]...) 379 for bitset, j := bitmap1|bitmap2, 0; bitset != 0; j++ { 380 bit := bitset & -bitset 381 if bitmap2&bit != 0 { 382 // Add fields from branchData2 383 fieldBits := PartFlags(branchData2[pos2]) 384 newData = append(newData, byte(fieldBits)) 385 pos2++ 386 for i := 0; i < bits.OnesCount8(byte(fieldBits)); i++ { 387 l, n := binary.Uvarint(branchData2[pos2:]) 388 if n == 0 { 389 return nil, fmt.Errorf("MergeHexBranches buffer2 too small for field") 390 } else if n < 0 { 391 return nil, fmt.Errorf("MergeHexBranches value2 overflow for field") 392 } 393 newData = append(newData, branchData2[pos2:pos2+n]...) 394 pos2 += n 395 if len(branchData2) < pos2+int(l) { 396 return nil, fmt.Errorf("MergeHexBranches buffer2 too small for field") 397 } 398 if l > 0 { 399 newData = append(newData, branchData2[pos2:pos2+int(l)]...) 400 pos2 += int(l) 401 } 402 } 403 } 404 if bitmap1&bit != 0 { 405 add := (touchMap2&bit == 0) && (afterMap2&bit != 0) // Add fields from branchData1 406 fieldBits := PartFlags(branchData[pos1]) 407 if add { 408 newData = append(newData, byte(fieldBits)) 409 } 410 pos1++ 411 for i := 0; i < bits.OnesCount8(byte(fieldBits)); i++ { 412 l, n := binary.Uvarint(branchData[pos1:]) 413 if n == 0 { 414 return nil, fmt.Errorf("MergeHexBranches buffer1 too small for field") 415 } else if n < 0 { 416 return nil, fmt.Errorf("MergeHexBranches value1 overflow for field") 417 } 418 if add { 419 newData = append(newData, branchData[pos1:pos1+n]...) 420 } 421 pos1 += n 422 if len(branchData) < pos1+int(l) { 423 return nil, fmt.Errorf("MergeHexBranches buffer1 too small for field") 424 } 425 if l > 0 { 426 if add { 427 newData = append(newData, branchData[pos1:pos1+int(l)]...) 428 } 429 pos1 += int(l) 430 } 431 } 432 } 433 bitset ^= bit 434 } 435 return newData, nil 436 } 437 438 func (branchData BranchData) DecodeCells() (touchMap, afterMap uint16, row [16]*Cell, err error) { 439 touchMap = binary.BigEndian.Uint16(branchData[0:]) 440 afterMap = binary.BigEndian.Uint16(branchData[2:]) 441 pos := 4 442 for bitset, j := touchMap, 0; bitset != 0; j++ { 443 bit := bitset & -bitset 444 nibble := bits.TrailingZeros16(bit) 445 if afterMap&bit != 0 { 446 fieldBits := PartFlags(branchData[pos]) 447 pos++ 448 row[nibble] = new(Cell) 449 if pos, err = row[nibble].fillFromFields(branchData, pos, fieldBits); err != nil { 450 err = fmt.Errorf("faield to fill cell at nibble %x: %w", nibble, err) 451 return 452 } 453 } 454 bitset ^= bit 455 } 456 return 457 } 458 459 type BranchMerger struct { 460 buf *bytes.Buffer 461 num [4]byte 462 keccak hash.Hash 463 } 464 465 func NewHexBranchMerger(capacity uint64) *BranchMerger { 466 return &BranchMerger{buf: bytes.NewBuffer(make([]byte, capacity)), keccak: sha3.NewLegacyKeccak256()} 467 } 468 469 // MergeHexBranches combines two branchData, number 2 coming after (and potentially shadowing) number 1 470 func (m *BranchMerger) Merge(branch1 BranchData, branch2 BranchData) (BranchData, error) { 471 if branch2 == nil { 472 return branch1, nil 473 } 474 if branch1 == nil { 475 return branch2, nil 476 } 477 478 touchMap1 := binary.BigEndian.Uint16(branch1[0:]) 479 afterMap1 := binary.BigEndian.Uint16(branch1[2:]) 480 bitmap1 := touchMap1 & afterMap1 481 pos1 := 4 482 483 touchMap2 := binary.BigEndian.Uint16(branch2[0:]) 484 afterMap2 := binary.BigEndian.Uint16(branch2[2:]) 485 bitmap2 := touchMap2 & afterMap2 486 pos2 := 4 487 488 binary.BigEndian.PutUint16(m.num[0:], touchMap1|touchMap2) 489 binary.BigEndian.PutUint16(m.num[2:], afterMap2) 490 dataPos := 4 491 492 m.buf.Reset() 493 if _, err := m.buf.Write(m.num[:]); err != nil { 494 return nil, err 495 } 496 497 for bitset, j := bitmap1|bitmap2, 0; bitset != 0; j++ { 498 bit := bitset & -bitset 499 if bitmap2&bit != 0 { 500 // Add fields from branch2 501 fieldBits := PartFlags(branch2[pos2]) 502 if err := m.buf.WriteByte(byte(fieldBits)); err != nil { 503 return nil, err 504 } 505 pos2++ 506 507 for i := 0; i < bits.OnesCount8(byte(fieldBits)); i++ { 508 l, n := binary.Uvarint(branch2[pos2:]) 509 if n == 0 { 510 return nil, fmt.Errorf("MergeHexBranches branch2 is too small: expected node info size") 511 } else if n < 0 { 512 return nil, fmt.Errorf("MergeHexBranches branch2: size overflow for length") 513 } 514 515 _, err := m.buf.Write(branch2[pos2 : pos2+n]) 516 if err != nil { 517 return nil, err 518 } 519 pos2 += n 520 dataPos += n 521 if len(branch2) < pos2+int(l) { 522 return nil, fmt.Errorf("MergeHexBranches branch2 is too small: expected at least %d got %d bytes", pos2+int(l), len(branch2)) 523 } 524 if l > 0 { 525 if _, err := m.buf.Write(branch2[pos2 : pos2+int(l)]); err != nil { 526 return nil, err 527 } 528 pos2 += int(l) 529 dataPos += int(l) 530 } 531 } 532 } 533 if bitmap1&bit != 0 { 534 add := (touchMap2&bit == 0) && (afterMap2&bit != 0) // Add fields from branchData1 535 fieldBits := PartFlags(branch1[pos1]) 536 if add { 537 if err := m.buf.WriteByte(byte(fieldBits)); err != nil { 538 return nil, err 539 } 540 } 541 pos1++ 542 for i := 0; i < bits.OnesCount8(byte(fieldBits)); i++ { 543 l, n := binary.Uvarint(branch1[pos1:]) 544 if n == 0 { 545 return nil, fmt.Errorf("MergeHexBranches branch1 is too small: expected node info size") 546 } else if n < 0 { 547 return nil, fmt.Errorf("MergeHexBranches branch1: size overflow for length") 548 } 549 if add { 550 if _, err := m.buf.Write(branch1[pos1 : pos1+n]); err != nil { 551 return nil, err 552 } 553 } 554 pos1 += n 555 if len(branch1) < pos1+int(l) { 556 return nil, fmt.Errorf("MergeHexBranches branch1 is too small: expected at least %d got %d bytes", pos1+int(l), len(branch1)) 557 } 558 if l > 0 { 559 if add { 560 if _, err := m.buf.Write(branch1[pos1 : pos1+int(l)]); err != nil { 561 return nil, err 562 } 563 } 564 pos1 += int(l) 565 } 566 } 567 } 568 bitset ^= bit 569 } 570 target := make([]byte, m.buf.Len()) 571 copy(target, m.buf.Bytes()) 572 return target, nil 573 } 574 575 func ParseTrieVariant(s string) TrieVariant { 576 var trieVariant TrieVariant 577 switch s { 578 case "bin": 579 trieVariant = VariantBinPatriciaTrie 580 case "hex": 581 fallthrough 582 default: 583 trieVariant = VariantHexPatriciaTrie 584 } 585 return trieVariant 586 }