github.com/MetalBlockchain/subnet-evm@v0.4.9/plugin/evm/block.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "context" 8 "fmt" 9 "math/big" 10 "time" 11 12 "github.com/ethereum/go-ethereum/log" 13 "github.com/ethereum/go-ethereum/rlp" 14 15 "github.com/MetalBlockchain/subnet-evm/core/types" 16 17 "github.com/MetalBlockchain/metalgo/ids" 18 "github.com/MetalBlockchain/metalgo/snow/choices" 19 ) 20 21 // Block implements the snowman.Block interface 22 type Block struct { 23 id ids.ID 24 ethBlock *types.Block 25 vm *VM 26 status choices.Status 27 } 28 29 // newBlock returns a new Block wrapping the ethBlock type and implementing the snowman.Block interface 30 func (vm *VM) newBlock(ethBlock *types.Block) *Block { 31 return &Block{ 32 id: ids.ID(ethBlock.Hash()), 33 ethBlock: ethBlock, 34 vm: vm, 35 } 36 } 37 38 // ID implements the snowman.Block interface 39 func (b *Block) ID() ids.ID { return b.id } 40 41 // Accept implements the snowman.Block interface 42 func (b *Block) Accept(context.Context) error { 43 vm := b.vm 44 45 // Although returning an error from Accept is considered fatal, it is good 46 // practice to cleanup the batch we were modifying in the case of an error. 47 defer vm.db.Abort() 48 49 b.status = choices.Accepted 50 log.Debug(fmt.Sprintf("Accepting block %s (%s) at height %d", b.ID().Hex(), b.ID(), b.Height())) 51 if err := vm.blockChain.Accept(b.ethBlock); err != nil { 52 return fmt.Errorf("chain could not accept %s: %w", b.ID(), err) 53 } 54 if err := vm.acceptedBlockDB.Put(lastAcceptedKey, b.id[:]); err != nil { 55 return fmt.Errorf("failed to put %s as the last accepted block: %w", b.ID(), err) 56 } 57 58 return vm.db.Commit() 59 } 60 61 // Reject implements the snowman.Block interface 62 func (b *Block) Reject(context.Context) error { 63 b.status = choices.Rejected 64 log.Debug(fmt.Sprintf("Rejecting block %s (%s) at height %d", b.ID().Hex(), b.ID(), b.Height())) 65 return b.vm.blockChain.Reject(b.ethBlock) 66 } 67 68 // SetStatus implements the InternalBlock interface allowing ChainState 69 // to set the status on an existing block 70 func (b *Block) SetStatus(status choices.Status) { b.status = status } 71 72 // Status implements the snowman.Block interface 73 func (b *Block) Status() choices.Status { 74 return b.status 75 } 76 77 // Parent implements the snowman.Block interface 78 func (b *Block) Parent() ids.ID { 79 return ids.ID(b.ethBlock.ParentHash()) 80 } 81 82 // Height implements the snowman.Block interface 83 func (b *Block) Height() uint64 { 84 return b.ethBlock.NumberU64() 85 } 86 87 // Timestamp implements the snowman.Block interface 88 func (b *Block) Timestamp() time.Time { 89 return time.Unix(int64(b.ethBlock.Time()), 0) 90 } 91 92 // syntacticVerify verifies that a *Block is well-formed. 93 func (b *Block) syntacticVerify() error { 94 if b == nil || b.ethBlock == nil { 95 return errInvalidBlock 96 } 97 98 header := b.ethBlock.Header() 99 rules := b.vm.chainConfig.AvalancheRules(header.Number, new(big.Int).SetUint64(header.Time)) 100 return b.vm.syntacticBlockValidator.SyntacticVerify(b, rules) 101 } 102 103 // Verify implements the snowman.Block interface 104 func (b *Block) Verify(context.Context) error { 105 return b.verify(true) 106 } 107 108 func (b *Block) verify(writes bool) error { 109 if err := b.syntacticVerify(); err != nil { 110 return fmt.Errorf("syntactic block verification failed: %w", err) 111 } 112 113 return b.vm.blockChain.InsertBlockManual(b.ethBlock, writes) 114 } 115 116 // Bytes implements the snowman.Block interface 117 func (b *Block) Bytes() []byte { 118 res, err := rlp.EncodeToBytes(b.ethBlock) 119 if err != nil { 120 panic(err) 121 } 122 return res 123 } 124 125 func (b *Block) String() string { return fmt.Sprintf("EVM block, ID = %s", b.ID()) }