github.com/ethxdao/go-ethereum@v0.0.0-20221218102228-5ae34a9cc189/cmd/evm/internal/t8ntool/block.go (about) 1 // Copyright 2021 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 t8ntool 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math/big" 25 "os" 26 27 "github.com/ethxdao/go-ethereum/common" 28 "github.com/ethxdao/go-ethereum/common/hexutil" 29 "github.com/ethxdao/go-ethereum/common/math" 30 "github.com/ethxdao/go-ethereum/consensus/clique" 31 "github.com/ethxdao/go-ethereum/consensus/ethash" 32 "github.com/ethxdao/go-ethereum/core/types" 33 "github.com/ethxdao/go-ethereum/crypto" 34 "github.com/ethxdao/go-ethereum/log" 35 "github.com/ethxdao/go-ethereum/rlp" 36 ) 37 38 //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go 39 type header struct { 40 ParentHash common.Hash `json:"parentHash"` 41 OmmerHash *common.Hash `json:"sha3Uncles"` 42 Coinbase *common.Address `json:"miner"` 43 Root common.Hash `json:"stateRoot" gencodec:"required"` 44 TxHash *common.Hash `json:"transactionsRoot"` 45 ReceiptHash *common.Hash `json:"receiptsRoot"` 46 Bloom types.Bloom `json:"logsBloom"` 47 Difficulty *big.Int `json:"difficulty"` 48 Number *big.Int `json:"number" gencodec:"required"` 49 GasLimit uint64 `json:"gasLimit" gencodec:"required"` 50 GasUsed uint64 `json:"gasUsed"` 51 Time uint64 `json:"timestamp" gencodec:"required"` 52 Extra []byte `json:"extraData"` 53 MixDigest common.Hash `json:"mixHash"` 54 Nonce *types.BlockNonce `json:"nonce"` 55 BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` 56 } 57 58 type headerMarshaling struct { 59 Difficulty *math.HexOrDecimal256 60 Number *math.HexOrDecimal256 61 GasLimit math.HexOrDecimal64 62 GasUsed math.HexOrDecimal64 63 Time math.HexOrDecimal64 64 Extra hexutil.Bytes 65 BaseFee *math.HexOrDecimal256 66 } 67 68 type bbInput struct { 69 Header *header `json:"header,omitempty"` 70 OmmersRlp []string `json:"ommers,omitempty"` 71 TxRlp string `json:"txs,omitempty"` 72 Clique *cliqueInput `json:"clique,omitempty"` 73 74 Ethash bool `json:"-"` 75 EthashDir string `json:"-"` 76 PowMode ethash.Mode `json:"-"` 77 Txs []*types.Transaction `json:"-"` 78 Ommers []*types.Header `json:"-"` 79 } 80 81 type cliqueInput struct { 82 Key *ecdsa.PrivateKey 83 Voted *common.Address 84 Authorize *bool 85 Vanity common.Hash 86 } 87 88 // UnmarshalJSON implements json.Unmarshaler interface. 89 func (c *cliqueInput) UnmarshalJSON(input []byte) error { 90 var x struct { 91 Key *common.Hash `json:"secretKey"` 92 Voted *common.Address `json:"voted"` 93 Authorize *bool `json:"authorize"` 94 Vanity common.Hash `json:"vanity"` 95 } 96 if err := json.Unmarshal(input, &x); err != nil { 97 return err 98 } 99 if x.Key == nil { 100 return errors.New("missing required field 'secretKey' for cliqueInput") 101 } 102 if ecdsaKey, err := crypto.ToECDSA(x.Key[:]); err != nil { 103 return err 104 } else { 105 c.Key = ecdsaKey 106 } 107 c.Voted = x.Voted 108 c.Authorize = x.Authorize 109 c.Vanity = x.Vanity 110 return nil 111 } 112 113 // ToBlock converts i into a *types.Block 114 func (i *bbInput) ToBlock() *types.Block { 115 header := &types.Header{ 116 ParentHash: i.Header.ParentHash, 117 UncleHash: types.EmptyUncleHash, 118 Coinbase: common.Address{}, 119 Root: i.Header.Root, 120 TxHash: types.EmptyRootHash, 121 ReceiptHash: types.EmptyRootHash, 122 Bloom: i.Header.Bloom, 123 Difficulty: common.Big0, 124 Number: i.Header.Number, 125 GasLimit: i.Header.GasLimit, 126 GasUsed: i.Header.GasUsed, 127 Time: i.Header.Time, 128 Extra: i.Header.Extra, 129 MixDigest: i.Header.MixDigest, 130 BaseFee: i.Header.BaseFee, 131 } 132 133 // Fill optional values. 134 if i.Header.OmmerHash != nil { 135 header.UncleHash = *i.Header.OmmerHash 136 } else if len(i.Ommers) != 0 { 137 // Calculate the ommer hash if none is provided and there are ommers to hash 138 header.UncleHash = types.CalcUncleHash(i.Ommers) 139 } 140 if i.Header.Coinbase != nil { 141 header.Coinbase = *i.Header.Coinbase 142 } 143 if i.Header.TxHash != nil { 144 header.TxHash = *i.Header.TxHash 145 } 146 if i.Header.ReceiptHash != nil { 147 header.ReceiptHash = *i.Header.ReceiptHash 148 } 149 if i.Header.Nonce != nil { 150 header.Nonce = *i.Header.Nonce 151 } 152 if header.Difficulty != nil { 153 header.Difficulty = i.Header.Difficulty 154 } 155 return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers) 156 } 157 158 // SealBlock seals the given block using the configured engine. 159 func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) { 160 switch { 161 case i.Ethash: 162 return i.sealEthash(block) 163 case i.Clique != nil: 164 return i.sealClique(block) 165 default: 166 return block, nil 167 } 168 } 169 170 // sealEthash seals the given block using ethash. 171 func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) { 172 if i.Header.Nonce != nil { 173 return nil, NewError(ErrorConfig, fmt.Errorf("sealing with ethash will overwrite provided nonce")) 174 } 175 ethashConfig := ethash.Config{ 176 PowMode: i.PowMode, 177 DatasetDir: i.EthashDir, 178 CacheDir: i.EthashDir, 179 DatasetsInMem: 1, 180 DatasetsOnDisk: 2, 181 CachesInMem: 2, 182 CachesOnDisk: 3, 183 } 184 engine := ethash.New(ethashConfig, nil, true) 185 defer engine.Close() 186 // Use a buffered chan for results. 187 // If the testmode is used, the sealer will return quickly, and complain 188 // "Sealing result is not read by miner" if it cannot write the result. 189 results := make(chan *types.Block, 1) 190 if err := engine.Seal(nil, block, results, nil); err != nil { 191 panic(fmt.Sprintf("failed to seal block: %v", err)) 192 } 193 found := <-results 194 return block.WithSeal(found.Header()), nil 195 } 196 197 // sealClique seals the given block using clique. 198 func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) { 199 // If any clique value overwrites an explicit header value, fail 200 // to avoid silently building a block with unexpected values. 201 if i.Header.Extra != nil { 202 return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique will overwrite provided extra data")) 203 } 204 header := block.Header() 205 if i.Clique.Voted != nil { 206 if i.Header.Coinbase != nil { 207 return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided coinbase")) 208 } 209 header.Coinbase = *i.Clique.Voted 210 } 211 if i.Clique.Authorize != nil { 212 if i.Header.Nonce != nil { 213 return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided nonce")) 214 } 215 if *i.Clique.Authorize { 216 header.Nonce = [8]byte{} 217 } else { 218 header.Nonce = [8]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} 219 } 220 } 221 // Extra is fixed 32 byte vanity and 65 byte signature 222 header.Extra = make([]byte, 32+65) 223 copy(header.Extra[0:32], i.Clique.Vanity.Bytes()[:]) 224 225 // Sign the seal hash and fill in the rest of the extra data 226 h := clique.SealHash(header) 227 sighash, err := crypto.Sign(h[:], i.Clique.Key) 228 if err != nil { 229 return nil, err 230 } 231 copy(header.Extra[32:], sighash) 232 block = block.WithSeal(header) 233 return block, nil 234 } 235 236 // BuildBlock constructs a block from the given inputs. 237 func BuildBlock(ctx *cli.Context) error { 238 // Configure the go-ethereum logger 239 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 240 glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) 241 log.Root().SetHandler(glogger) 242 243 baseDir, err := createBasedir(ctx) 244 if err != nil { 245 return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) 246 } 247 inputData, err := readInput(ctx) 248 if err != nil { 249 return err 250 } 251 block := inputData.ToBlock() 252 block, err = inputData.SealBlock(block) 253 if err != nil { 254 return err 255 } 256 return dispatchBlock(ctx, baseDir, block) 257 } 258 259 func readInput(ctx *cli.Context) (*bbInput, error) { 260 var ( 261 headerStr = ctx.String(InputHeaderFlag.Name) 262 ommersStr = ctx.String(InputOmmersFlag.Name) 263 txsStr = ctx.String(InputTxsRlpFlag.Name) 264 cliqueStr = ctx.String(SealCliqueFlag.Name) 265 ethashOn = ctx.Bool(SealEthashFlag.Name) 266 ethashDir = ctx.String(SealEthashDirFlag.Name) 267 ethashMode = ctx.String(SealEthashModeFlag.Name) 268 inputData = &bbInput{} 269 ) 270 if ethashOn && cliqueStr != "" { 271 return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen")) 272 } 273 if ethashOn { 274 inputData.Ethash = ethashOn 275 inputData.EthashDir = ethashDir 276 switch ethashMode { 277 case "normal": 278 inputData.PowMode = ethash.ModeNormal 279 case "test": 280 inputData.PowMode = ethash.ModeTest 281 case "fake": 282 inputData.PowMode = ethash.ModeFake 283 default: 284 return nil, NewError(ErrorConfig, fmt.Errorf("unknown pow mode: %s, supported modes: test, fake, normal", ethashMode)) 285 } 286 } 287 if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector { 288 decoder := json.NewDecoder(os.Stdin) 289 if err := decoder.Decode(inputData); err != nil { 290 return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) 291 } 292 } 293 if cliqueStr != stdinSelector && cliqueStr != "" { 294 var clique cliqueInput 295 if err := readFile(cliqueStr, "clique", &clique); err != nil { 296 return nil, err 297 } 298 inputData.Clique = &clique 299 } 300 if headerStr != stdinSelector { 301 var env header 302 if err := readFile(headerStr, "header", &env); err != nil { 303 return nil, err 304 } 305 inputData.Header = &env 306 } 307 if ommersStr != stdinSelector && ommersStr != "" { 308 var ommers []string 309 if err := readFile(ommersStr, "ommers", &ommers); err != nil { 310 return nil, err 311 } 312 inputData.OmmersRlp = ommers 313 } 314 if txsStr != stdinSelector { 315 var txs string 316 if err := readFile(txsStr, "txs", &txs); err != nil { 317 return nil, err 318 } 319 inputData.TxRlp = txs 320 } 321 // Deserialize rlp txs and ommers 322 var ( 323 ommers = []*types.Header{} 324 txs = []*types.Transaction{} 325 ) 326 if inputData.TxRlp != "" { 327 if err := rlp.DecodeBytes(common.FromHex(inputData.TxRlp), &txs); err != nil { 328 return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode transaction from rlp data: %v", err)) 329 } 330 inputData.Txs = txs 331 } 332 for _, str := range inputData.OmmersRlp { 333 type extblock struct { 334 Header *types.Header 335 Txs []*types.Transaction 336 Ommers []*types.Header 337 } 338 var ommer *extblock 339 if err := rlp.DecodeBytes(common.FromHex(str), &ommer); err != nil { 340 return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode ommer from rlp data: %v", err)) 341 } 342 ommers = append(ommers, ommer.Header) 343 } 344 inputData.Ommers = ommers 345 346 return inputData, nil 347 } 348 349 // dispatchOutput writes the output data to either stderr or stdout, or to the specified 350 // files 351 func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { 352 raw, _ := rlp.EncodeToBytes(block) 353 354 type blockInfo struct { 355 Rlp hexutil.Bytes `json:"rlp"` 356 Hash common.Hash `json:"hash"` 357 } 358 var enc blockInfo 359 enc.Rlp = raw 360 enc.Hash = block.Hash() 361 362 b, err := json.MarshalIndent(enc, "", " ") 363 if err != nil { 364 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 365 } 366 switch dest := ctx.String(OutputBlockFlag.Name); dest { 367 case "stdout": 368 os.Stdout.Write(b) 369 os.Stdout.WriteString("\n") 370 case "stderr": 371 os.Stderr.Write(b) 372 os.Stderr.WriteString("\n") 373 default: 374 if err := saveFile(baseDir, dest, enc); err != nil { 375 return err 376 } 377 } 378 return nil 379 }