github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/block/block.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package block
     7  
     8  import (
     9  	"time"
    10  
    11  	"github.com/iotexproject/go-pkgs/hash"
    12  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    13  	"github.com/pkg/errors"
    14  	"go.uber.org/zap"
    15  	"google.golang.org/protobuf/proto"
    16  
    17  	"github.com/iotexproject/iotex-core/action"
    18  	"github.com/iotexproject/iotex-core/endorsement"
    19  	"github.com/iotexproject/iotex-core/pkg/log"
    20  )
    21  
    22  // Block defines the struct of block
    23  type Block struct {
    24  	Header
    25  	Body
    26  	Footer
    27  
    28  	// TODO: move receipts out of block struct
    29  	Receipts []*action.Receipt
    30  }
    31  
    32  // ConvertToBlockPb converts Block to Block
    33  func (b *Block) ConvertToBlockPb() *iotextypes.Block {
    34  	footer, err := b.ConvertToBlockFooterPb()
    35  	if err != nil {
    36  		log.L().Panic("failed to convert block footer to protobuf message")
    37  	}
    38  	return &iotextypes.Block{
    39  		Header: b.Header.Proto(),
    40  		Body:   b.Body.Proto(),
    41  		Footer: footer,
    42  	}
    43  }
    44  
    45  // Serialize returns the serialized byte stream of the block
    46  func (b *Block) Serialize() ([]byte, error) {
    47  	return proto.Marshal(b.ConvertToBlockPb())
    48  }
    49  
    50  // VerifyTxRoot verifies the transaction root hash
    51  func (b *Block) VerifyTxRoot() error {
    52  	root, err := b.CalculateTxRoot()
    53  	if err != nil {
    54  		log.L().Debug("error in getting hash", zap.Error(err))
    55  		return err
    56  	}
    57  	if !b.Header.VerifyTransactionRoot(root) {
    58  		return ErrTxRootMismatch
    59  	}
    60  	return nil
    61  }
    62  
    63  // RunnableActions abstructs RunnableActions from a Block.
    64  func (b *Block) RunnableActions() RunnableActions {
    65  	return RunnableActions{actions: b.Actions, txHash: b.txRoot}
    66  }
    67  
    68  // Finalize creates a footer for the block
    69  func (b *Block) Finalize(endorsements []*endorsement.Endorsement, ts time.Time) error {
    70  	if len(b.endorsements) != 0 {
    71  		return errors.New("the block has been finalized")
    72  	}
    73  	b.endorsements = endorsements
    74  	b.commitTime = ts
    75  
    76  	return nil
    77  }
    78  
    79  // TransactionLog returns transaction logs in the block
    80  func (b *Block) TransactionLog() *BlkTransactionLog {
    81  	if len(b.Receipts) == 0 {
    82  		return nil
    83  	}
    84  
    85  	blkLog := BlkTransactionLog{
    86  		actionLogs: []*TransactionLog{},
    87  	}
    88  	for _, r := range b.Receipts {
    89  		if log := ReceiptTransactionLog(r); log != nil {
    90  			blkLog.actionLogs = append(blkLog.actionLogs, log)
    91  		}
    92  	}
    93  
    94  	if len(blkLog.actionLogs) == 0 {
    95  		return nil
    96  	}
    97  	return &blkLog
    98  }
    99  
   100  // ActionByHash returns the action of a given hash
   101  func (b *Block) ActionByHash(h hash.Hash256) (*action.SealedEnvelope, uint32, error) {
   102  	for i, act := range b.Actions {
   103  		actHash, err := act.Hash()
   104  		if err != nil {
   105  			return nil, 0, errors.Errorf("hash failed for action %d", i)
   106  		}
   107  		if actHash == h {
   108  			return act, uint32(i), nil
   109  		}
   110  	}
   111  	return nil, 0, errors.Errorf("block does not have action %x", h)
   112  }