From 8fe1d04b12322a97d662a9612e539a667119ce07 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Mon, 3 Jun 2024 12:02:28 +0300 Subject: [PATCH] Handle elided transactions during block processing. --- pkg/state/appender.go | 29 +++++++++++++++++++++-------- pkg/state/state.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/pkg/state/appender.go b/pkg/state/appender.go index 71dfca60a8..3e1f538fa1 100644 --- a/pkg/state/appender.go +++ b/pkg/state/appender.go @@ -679,6 +679,7 @@ func (a *txAppender) appendTxs( if err != nil { return proto.BlockSnapshot{}, crypto.Digest{}, err } + _, isBlockWithChallenge := params.block.GetChallengedHeader() // Check and append transactions. var bs proto.BlockSnapshot appendTxArgs := &appendTxParams{ @@ -697,22 +698,34 @@ func (a *txAppender) appendTxs( currentMinerPK: params.block.GeneratorPublicKey, } for _, tx := range params.transactions { - txSnapshots, errAppendTx := a.appendTx(tx, appendTxArgs) - if errAppendTx != nil { - return proto.BlockSnapshot{}, crypto.Digest{}, errAppendTx - } - bs.AppendTxSnapshot(txSnapshots.regular) - txID, idErr := tx.GetID(a.settings.AddressSchemeCharacter) if idErr != nil { return proto.BlockSnapshot{}, crypto.Digest{}, idErr } - if len(txSnapshots.regular) == 0 { // sanity check + txSnap, errAppendTx := a.appendTx(tx, appendTxArgs) + if errAppendTx != nil { // TODO: check error type for elided tx + if !isBlockWithChallenge { + return proto.BlockSnapshot{}, crypto.Digest{}, errAppendTx + } + txSnap = txSnapshot{ + regular: []proto.AtomicSnapshot{ + &proto.TransactionStatusSnapshot{Status: proto.TransactionElided}, + }, + internal: nil, + } + if aErr := txSnap.Apply(a.txHandler.sa, tx, appendTxArgs.validatingUtx); aErr != nil { + return proto.BlockSnapshot{}, crypto.Digest{}, + errors.Wrapf(aErr, "failed to apply elided tx (ID=%q) snapshot", base58.Encode(txID)) + } + } + bs.AppendTxSnapshot(txSnap.regular) + + if len(txSnap.regular) == 0 { // sanity check return proto.BlockSnapshot{}, crypto.Digest{}, errors.Errorf("snapshot of txID %q cannot be empty", base58.Encode(txID)) } - txSh, shErr := calculateTxSnapshotStateHash(hasher, txID, blockInfo.Height, stateHash, txSnapshots.regular) + txSh, shErr := calculateTxSnapshotStateHash(hasher, txID, blockInfo.Height, stateHash, txSnap.regular) if shErr != nil { return proto.BlockSnapshot{}, crypto.Digest{}, errors.Wrapf(shErr, "failed to calculate tx snapshot hash for txID %q at height %d", base58.Encode(txID), blockInfo.Height, diff --git a/pkg/state/state.go b/pkg/state/state.go index f9b2ece98c..4870200233 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1242,6 +1242,11 @@ func (s *stateManager) beforeAppendBlock(block *proto.Block, blockHeight proto.H if err := s.stor.scores.appendBlockScore(block, blockHeight); err != nil { return err } + // Handle challenged header if it exists. + // Light node fields check performed in ValidateHeaderBeforeBlockApplying. + if chErr := s.handleChallengedHeaderIfExists(block, blockHeight); chErr != nil { + return chErr + } // Indicate new block for storage. if err := s.rw.startBlock(block.BlockID()); err != nil { return err @@ -1250,6 +1255,36 @@ func (s *stateManager) beforeAppendBlock(block *proto.Block, blockHeight proto.H return s.rw.writeBlockHeader(&block.BlockHeader) } +func (s *stateManager) handleChallengedHeaderIfExists(block *proto.Block, blockHeight proto.Height) error { + challengedHeader, ok := block.GetChallengedHeader() + if !ok { // nothing to do, no challenge to handle + return nil + } + var ( + scheme = s.settings.AddressSchemeCharacter + blockID = block.BlockID() + ) + challenger, err := proto.NewAddressFromPublicKey(scheme, block.GeneratorPublicKey) + if err != nil { + return errors.Wrapf(err, "failed to create challenger address from public key '%s'", + challengedHeader.GeneratorPublicKey.String(), + ) + } + challenged, err := proto.NewAddressFromPublicKey(scheme, challengedHeader.GeneratorPublicKey) + if err != nil { + return errors.Wrapf(err, "failed to create challenged address from public key '%s'", + challengedHeader.GeneratorPublicKey.String(), + ) + } + if chErr := s.stor.balances.storeChallenge(challenger.ID(), challenged.ID(), blockHeight, blockID); chErr != nil { + return errors.Wrapf(chErr, + "failed to store challenge for block '%s' at height %d with challenger '%s' and challenged '%s'", + blockID.String(), blockHeight, challenger.String(), challenged.String(), + ) + } + return nil +} + func (s *stateManager) afterAppendBlock(block *proto.Block, blockHeight proto.Height) error { // Let block storage know that the current block is over. if err := s.rw.finishBlock(block.BlockID()); err != nil {