Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Non-breaking changes] Optimize receipt storing #368

Closed
wants to merge 17 commits into from
Closed

[Non-breaking changes] Optimize receipt storing #368

wants to merge 17 commits into from

Conversation

trinhdn2
Copy link

@trinhdn2 trinhdn2 commented Jul 14, 2023

This PR attemps reduce the size of RLP encoded transaction receipts, also backwards compatibility is ensured.

These PRs must be merged first:

Instead of storing a full RLP encoded receipt including

type legacyStoredReceiptRLP struct {
	PostStateOrStatus []byte
	CumulativeGasUsed uint64
	Bloom             Bloom
	TxHash            common.Hash
	ContractAddress   common.Address
	Logs              []*LogForStorage
	GasUsed           uint64
}

we only need to store these crucial fields

type StoredReceiptRLP struct {
	PostStateOrStatus []byte
	CumulativeGasUsed uint64
	Logs              []*Log
}

the rest information can be derived from context and chain config

// DeriveFields fills the receipts with their computed fields based on consensus
// data and contextual infos like containing block and transactions.
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs []*Transaction) error {
	signer := MakeSigner(config, new(big.Int).SetUint64(number))

	logIndex := uint(0)
	if len(txs) != len(rs) {
		return errors.New("transaction and receipt count mismatch")
	}
	for i := 0; i < len(rs); i++ {
		// The transaction type and hash can be retrieved from the transaction itself
		rs[i].TxHash = txs[i].Hash()

		// block location fields
		rs[i].BlockHash = hash
		rs[i].BlockNumber = new(big.Int).SetUint64(number)
		rs[i].TransactionIndex = uint(i)

		// The contract address can be derived from the transaction itself
		if txs[i].To() == nil {
			// Deriving the signer is expensive, only do if it's actually needed
			from, _ := Sender(signer, txs[i])
			rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
		} else {
			rs[i].ContractAddress = common.Address{}
		}

		// The used gas can be calculated based on previous r
		if i == 0 {
			rs[i].GasUsed = rs[i].CumulativeGasUsed
		} else {
			rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
		}

		// The derived log fields can simply be set from the block and transaction
		for j := 0; j < len(rs[i].Logs); j++ {
			rs[i].Logs[j].BlockNumber = number
			rs[i].Logs[j].BlockHash = hash
			rs[i].Logs[j].TxHash = rs[i].TxHash
			rs[i].Logs[j].TxIndex = uint(i)
			rs[i].Logs[j].Index = logIndex
			logIndex++
		}
	}
	return nil
}

The backwards compatibility of the DecodeRLP method of a receipt is ensured. It will try to RLP decode based on the new receipt format first, if there is any error it will use the old legacyLegacyStoredReceipt RLP format.

// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
	// Retrieve the entire receipt blob as we need to try multiple decoders
	blob, err := s.Raw()
	if err != nil {
		return err
	}
	// Try decoding from the newest format for future proofness, then the older one
	// for old nodes that just upgraded. V4 was an intermediate unreleased format so
	// we do need to decode it, but it's not common (try last).
	if err := decodeStoredReceiptRLP(r, blob); err == nil {
		return nil
	}
	return decodeLegacyStoredReceiptRLP(r, blob)
}

@trinhdn2 trinhdn2 changed the base branch from master to upgrade-core-develop July 14, 2023 19:44
@trinhdn2 trinhdn2 changed the title Optimize receipt storing [Non-breaking changes] Optimize receipt storing Jul 14, 2023
@trinhdn2 trinhdn2 marked this pull request as ready for review July 16, 2023 14:20
@tungng98 tungng98 added the non-breaking Enhancement that doesn't need a hardfork label Jul 16, 2023
@tungng98 tungng98 deleted the branch BuildOnViction:upgrade-core-develop December 10, 2023 16:51
@tungng98 tungng98 closed this Dec 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
non-breaking Enhancement that doesn't need a hardfork
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants