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