github.com/calmw/ethereum@v0.1.1/cmd/geth/verkle.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "errors" 23 "fmt" 24 "os" 25 26 "github.com/calmw/ethereum/cmd/utils" 27 "github.com/calmw/ethereum/common" 28 "github.com/calmw/ethereum/core/rawdb" 29 "github.com/calmw/ethereum/internal/flags" 30 "github.com/calmw/ethereum/log" 31 "github.com/gballet/go-verkle" 32 cli "github.com/urfave/cli/v2" 33 ) 34 35 var ( 36 zero [32]byte 37 38 verkleCommand = &cli.Command{ 39 Name: "verkle", 40 Usage: "A set of experimental verkle tree management commands", 41 Description: "", 42 Subcommands: []*cli.Command{ 43 { 44 Name: "verify", 45 Usage: "verify the conversion of a MPT into a verkle tree", 46 ArgsUsage: "<root>", 47 Action: verifyVerkle, 48 Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), 49 Description: ` 50 geth verkle verify <state-root> 51 This command takes a root commitment and attempts to rebuild the tree. 52 `, 53 }, 54 { 55 Name: "dump", 56 Usage: "Dump a verkle tree to a DOT file", 57 ArgsUsage: "<root> <key1> [<key 2> ...]", 58 Action: expandVerkle, 59 Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), 60 Description: ` 61 geth verkle dump <state-root> <key 1> [<key 2> ...] 62 This command will produce a dot file representing the tree, rooted at <root>. 63 in which key1, key2, ... are expanded. 64 `, 65 }, 66 }, 67 } 68 ) 69 70 // recurse into each child to ensure they can be loaded from the db. The tree isn't rebuilt 71 // (only its nodes are loaded) so there is no need to flush them, the garbage collector should 72 // take care of that for us. 73 func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error { 74 switch node := root.(type) { 75 case *verkle.InternalNode: 76 for i, child := range node.Children() { 77 childC := child.ComputeCommitment().Bytes() 78 79 childS, err := resolver(childC[:]) 80 if bytes.Equal(childC[:], zero[:]) { 81 continue 82 } 83 if err != nil { 84 return fmt.Errorf("could not find child %x in db: %w", childC, err) 85 } 86 // depth is set to 0, the tree isn't rebuilt so it's not a problem 87 childN, err := verkle.ParseNode(childS, 0, childC[:]) 88 if err != nil { 89 return fmt.Errorf("decode error child %x in db: %w", child.ComputeCommitment().Bytes(), err) 90 } 91 if err := checkChildren(childN, resolver); err != nil { 92 return fmt.Errorf("%x%w", i, err) // write the path to the erroring node 93 } 94 } 95 case *verkle.LeafNode: 96 // sanity check: ensure at least one value is non-zero 97 98 for i := 0; i < verkle.NodeWidth; i++ { 99 if len(node.Value(i)) != 0 { 100 return nil 101 } 102 } 103 return fmt.Errorf("Both balance and nonce are 0") 104 case verkle.Empty: 105 // nothing to do 106 default: 107 return fmt.Errorf("unsupported type encountered %v", root) 108 } 109 110 return nil 111 } 112 113 func verifyVerkle(ctx *cli.Context) error { 114 stack, _ := makeConfigNode(ctx) 115 defer stack.Close() 116 117 chaindb := utils.MakeChainDatabase(ctx, stack, true) 118 headBlock := rawdb.ReadHeadBlock(chaindb) 119 if headBlock == nil { 120 log.Error("Failed to load head block") 121 return errors.New("no head block") 122 } 123 if ctx.NArg() > 1 { 124 log.Error("Too many arguments given") 125 return errors.New("too many arguments") 126 } 127 var ( 128 rootC common.Hash 129 err error 130 ) 131 if ctx.NArg() == 1 { 132 rootC, err = parseRoot(ctx.Args().First()) 133 if err != nil { 134 log.Error("Failed to resolve state root", "error", err) 135 return err 136 } 137 log.Info("Rebuilding the tree", "root", rootC) 138 } else { 139 rootC = headBlock.Root() 140 log.Info("Rebuilding the tree", "root", rootC, "number", headBlock.NumberU64()) 141 } 142 143 serializedRoot, err := chaindb.Get(rootC[:]) 144 if err != nil { 145 return err 146 } 147 root, err := verkle.ParseNode(serializedRoot, 0, rootC[:]) 148 if err != nil { 149 return err 150 } 151 152 if err := checkChildren(root, chaindb.Get); err != nil { 153 log.Error("Could not rebuild the tree from the database", "err", err) 154 return err 155 } 156 157 log.Info("Tree was rebuilt from the database") 158 return nil 159 } 160 161 func expandVerkle(ctx *cli.Context) error { 162 stack, _ := makeConfigNode(ctx) 163 defer stack.Close() 164 165 chaindb := utils.MakeChainDatabase(ctx, stack, true) 166 var ( 167 rootC common.Hash 168 keylist [][]byte 169 err error 170 ) 171 if ctx.NArg() >= 2 { 172 rootC, err = parseRoot(ctx.Args().First()) 173 if err != nil { 174 log.Error("Failed to resolve state root", "error", err) 175 return err 176 } 177 keylist = make([][]byte, 0, ctx.Args().Len()-1) 178 args := ctx.Args().Slice() 179 for i := range args[1:] { 180 key, err := hex.DecodeString(args[i+1]) 181 log.Info("decoded key", "arg", args[i+1], "key", key) 182 if err != nil { 183 return fmt.Errorf("error decoding key #%d: %w", i+1, err) 184 } 185 keylist = append(keylist, key) 186 } 187 log.Info("Rebuilding the tree", "root", rootC) 188 } else { 189 return fmt.Errorf("usage: %s root key1 [key 2...]", ctx.App.Name) 190 } 191 192 serializedRoot, err := chaindb.Get(rootC[:]) 193 if err != nil { 194 return err 195 } 196 root, err := verkle.ParseNode(serializedRoot, 0, rootC[:]) 197 if err != nil { 198 return err 199 } 200 201 for i, key := range keylist { 202 log.Info("Reading key", "index", i, "key", keylist[0]) 203 root.Get(key, chaindb.Get) 204 } 205 206 if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil { 207 log.Error("Failed to dump file", "err", err) 208 } else { 209 log.Info("Tree was dumped to file", "file", "dump.dot") 210 } 211 return nil 212 }