Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,11 @@ func (m callMsg) IsL1MessageTx() bool { return false }
func (m callMsg) SetCodeAuthorizations() []types.SetCodeAuthorization {
return m.CallMsg.AuthorizationList
}
func (m callMsg) FeeTokenID() uint16 { return m.CallMsg.FeeTokenID }
func (m callMsg) FeeLimit() *big.Int { return m.CallMsg.FeeLimit }
func (m callMsg) FeeTokenID() uint16 { return m.CallMsg.FeeTokenID }
func (m callMsg) FeeLimit() *big.Int { return m.CallMsg.FeeLimit }
func (m callMsg) Version() byte { return m.CallMsg.Version }
func (m callMsg) Reference() *common.Reference { return m.CallMsg.Reference }
func (m callMsg) Memo() []byte { return m.CallMsg.Memo }

// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
Expand Down
18 changes: 12 additions & 6 deletions accounts/abi/bind/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ type TransactOpts struct {
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)

FeeTokenID uint16 // alt fee token id of transaction execution
FeeLimit *big.Int // alt fee token limit of transaction execution
FeeTokenID uint16 // alt fee token id of transaction execution
FeeLimit *big.Int // alt fee token limit of transaction execution
Version byte // version of morph tx
Reference *common.Reference // reference key for the transaction (optional)
Memo []byte // memo for the transaction (optional)

Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)

Expand Down Expand Up @@ -290,7 +293,7 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add
return types.NewTx(baseTx), nil
}

func (c *BoundContract) createAltFeeTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) {
func (c *BoundContract) createMorphTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) {
// Normalize value
value := opts.Value
if value == nil {
Expand Down Expand Up @@ -334,14 +337,17 @@ func (c *BoundContract) createAltFeeTx(opts *TransactOpts, contract *common.Addr
if err != nil {
return nil, err
}
baseTx := &types.AltFeeTx{
baseTx := &types.MorphTx{
To: contract,
Nonce: nonce,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
FeeTokenID: opts.FeeTokenID,
FeeLimit: opts.FeeLimit,
Gas: gasLimit,
Version: opts.Version,
Reference: opts.Reference,
Memo: opts.Memo,
Value: value,
Data: input,
}
Expand Down Expand Up @@ -438,8 +444,8 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil {
return nil, errHead
} else if head.BaseFee != nil {
if opts.FeeTokenID != 0 {
rawTx, err = c.createAltFeeTx(opts, contract, input, head)
if opts.FeeTokenID != 0 || opts.Version != 0 || opts.Reference != nil || len(opts.Memo) > 0 {
rawTx, err = c.createMorphTx(opts, contract, input, head)
} else {
rawTx, err = c.createDynamicTx(opts, contract, input, head)
}
Expand Down
6 changes: 5 additions & 1 deletion accounts/external/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,16 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
case types.DynamicFeeTxType, types.SetCodeTxType:
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
case types.AltFeeTxType:
case types.MorphTxType:
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
feeTokenID := hexutil.Uint16(tx.FeeTokenID())
args.FeeTokenID = &feeTokenID
args.FeeLimit = (*hexutil.Big)(tx.FeeLimit())
args.Version = tx.Version()
args.Reference = tx.Reference()
memo := hexutil.Bytes(tx.Memo())
args.Memo = &memo
default:
return nil, fmt.Errorf("unsupported tx type %d", tx.Type())
}
Expand Down
18 changes: 12 additions & 6 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,18 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
receipt.TxHash = tx.Hash()
receipt.GasUsed = msgResult.UsedGas
receipt.L1Fee = msgResult.L1DataFee
if msg.FeeTokenID() != 0 {
tokenID := msg.FeeTokenID()
receipt.FeeTokenID = &tokenID
receipt.FeeLimit = msg.FeeLimit()
receipt.FeeRate = msgResult.FeeRate
receipt.TokenScale = msgResult.TokenScale

if msg.FeeTokenID() != 0 || msg.Version() != 0 || msg.Reference() != nil || len(msg.Memo()) > 0 {
if msg.FeeTokenID() != 0 {
tokenID := msg.FeeTokenID()
receipt.FeeTokenID = &tokenID
receipt.FeeLimit = msg.FeeLimit()
receipt.FeeRate = msgResult.FeeRate
receipt.TokenScale = msgResult.TokenScale
}
receipt.Version = msg.Version()
receipt.Reference = msg.Reference()
receipt.Memo = msg.Memo()
}

// If the transaction created a contract, store the creation address in the receipt.
Expand Down
163 changes: 161 additions & 2 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,172 @@ const (
HashLength = 32
// AddressLength is the expected length of the address
AddressLength = 20
// ReferenceLength is the expected length of the reference
ReferenceLength = 32
)

var (
hashT = reflect.TypeOf(Hash{})
addressT = reflect.TypeOf(Address{})
hashT = reflect.TypeOf(Hash{})
addressT = reflect.TypeOf(Address{})
referenceT = reflect.TypeOf(Reference{})
)

// Reference represents the 32 byte reference of a transaction.
type Reference [ReferenceLength]byte

// BytesToReference sets b to reference.
// If b is larger than len(r), b will be cropped from the left.
func BytesToReference(b []byte) Reference {
var r Reference
r.SetBytes(b)
return r
}

// BigToReference sets byte representation of b to reference.
// If b is larger than len(r), b will be cropped from the left.
func BigToReference(b *big.Int) Reference { return BytesToReference(b.Bytes()) }

// HexToReference sets byte representation of s to reference.
// If b is larger than len(r), b will be cropped from the left.
func HexToReference(s string) Reference { return BytesToReference(FromHex(s)) }

// Bytes gets the byte representation of the underlying reference.
func (r Reference) Bytes() []byte { return r[:] }

// Big converts a reference to a big integer.
func (r Reference) Big() *big.Int { return new(big.Int).SetBytes(r[:]) }

// Hex converts a reference to a hex string.
func (r Reference) Hex() string { return hexutil.Encode(r[:]) }

// TerminalString implements log.TerminalStringer, formatting a string for console
// output during logging.
func (r Reference) TerminalString() string {
return fmt.Sprintf("%x..%x", r[:3], r[29:])
}

// String implements the stringer interface and is used also by the logger when
// doing full logging into a file.
func (r Reference) String() string {
return r.Hex()
}

// Format implements fmt.Formatter.
// Reference supports the %v, %s, %q, %x, %X and %d format verbs.
func (r Reference) Format(s fmt.State, c rune) {
hexb := make([]byte, 2+len(r)*2)
copy(hexb, "0x")
hex.Encode(hexb[2:], r[:])

switch c {
case 'x', 'X':
if !s.Flag('#') {
hexb = hexb[2:]
}
if c == 'X' {
hexb = bytes.ToUpper(hexb)
}
fallthrough
case 'v', 's':
s.Write(hexb)
case 'q':
q := []byte{'"'}
s.Write(q)
s.Write(hexb)
s.Write(q)
case 'd':
fmt.Fprint(s, ([len(r)]byte)(r))
default:
fmt.Fprintf(s, "%%!%c(reference=%x)", c, r)
}
}

// SetBytes sets the reference to the value of b.
// If b is larger than len(r), b will be cropped from the left.
func (r *Reference) SetBytes(b []byte) {
if len(b) > len(r) {
b = b[len(b)-ReferenceLength:]
}
copy(r[:], b)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// UnmarshalText parses a reference in hex syntax.
func (r *Reference) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("Reference", input, r[:])
}

// UnmarshalJSON parses a reference in hex syntax.
func (r *Reference) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(referenceT, input, r[:])
}

// MarshalText returns the hex representation of r.
func (r Reference) MarshalText() ([]byte, error) {
return hexutil.Bytes(r[:]).MarshalText()
}

// MarshalJSON marshals the original value

// MarshalJSON marshals the original value
func (r Reference) MarshalJSON() ([]byte, error) {
return json.Marshal(r.Hex())
}

// Generate implements testing/quick.Generator.
func (r Reference) Generate(rand *rand.Rand, size int) reflect.Value {
m := rand.Intn(len(r))
for i := len(r) - 1; i > m; i-- {
r[i] = byte(rand.Uint32())
}
return reflect.ValueOf(r)
}

// Scan implements Scanner for database/sql.
func (r *Reference) Scan(src interface{}) error {
srcB, ok := src.([]byte)
if !ok {
return fmt.Errorf("can't scan %T into Reference", src)
}
if len(srcB) != ReferenceLength {
return fmt.Errorf("can't scan []byte of len %d into Reference, want %d", len(srcB), ReferenceLength)
}
copy(r[:], srcB)
return nil
}

// Value implements valuer for database/sql.
func (r Reference) Value() (driver.Value, error) {
return r[:], nil
}

// ImplementsGraphQLType returns true if Reference implements the specified GraphQL type.
func (Reference) ImplementsGraphQLType(name string) bool { return name == "Bytes32" }

// UnmarshalGraphQL unmarshals the provided GraphQL query data.
func (r *Reference) UnmarshalGraphQL(input interface{}) error {
var err error
switch input := input.(type) {
case string:
err = r.UnmarshalText([]byte(input))
default:
err = fmt.Errorf("unexpected type %T for Reference", input)
}
return err
}

// UnprefixedReference allows marshaling a Reference without 0x prefix.
type UnprefixedReference Reference

// UnmarshalText decodes the reference from hex. The 0x prefix is optional.
func (r *UnprefixedReference) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedUnprefixedText("UnprefixedReference", input, r[:])
}

// MarshalText encodes the reference as hex.
func (r UnprefixedReference) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(r[:])), nil
}

// Hash represents the 32 byte Keccak256 hash of arbitrary data.
type Hash [HashLength]byte

Expand Down
94 changes: 94 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
go bc.maintainTxIndex(txIndexBlock)
}

// Start reference indexer/unindexer (using same lookup limit as tx index).
if txLookupLimit != nil {
bc.wg.Add(1)
go bc.maintainReferenceIndex(txIndexBlock)
}

// If periodic cache journal is required, spin it up.
if bc.cacheConfig.TrieCleanRejournal > 0 {
if bc.cacheConfig.TrieCleanRejournal < time.Minute {
Expand Down Expand Up @@ -2134,6 +2140,94 @@ func (bc *BlockChain) maintainTxIndex(ancients uint64) {
}
}

// maintainReferenceIndex is responsible for the construction and deletion of the
// reference index for MorphTx transactions.
//
// User can use flag `txlookuplimit` to specify a "recentness" block, below
// which ancient reference indices get deleted. If `txlookuplimit` is 0, it means
// all reference indices will be reserved.
//
// The user can adjust the txlookuplimit value for each launch after fast
// sync, Geth will automatically construct the missing indices and delete
// the extra indices.
func (bc *BlockChain) maintainReferenceIndex(ancients uint64) {
defer bc.wg.Done()

// Before starting the actual maintenance, we need to handle a special case,
// where user might init Geth with an external ancient database. If so, we
// need to reindex all necessary references before starting to process any
// pruning requests.
if ancients > 0 {
var from = uint64(0)
if bc.txLookupLimit != 0 && ancients > bc.txLookupLimit {
from = ancients - bc.txLookupLimit
}
rawdb.IndexReferences(bc.db, from, ancients, bc.quit)
}

// indexBlocks reindexes or unindexes references depending on user configuration
indexBlocks := func(tail *uint64, head uint64, done chan struct{}) {
defer func() { done <- struct{}{} }()

// If the user just upgraded Geth to a new version which supports reference
// index pruning, write the new tail and remove anything older.
if tail == nil {
if bc.txLookupLimit == 0 || head < bc.txLookupLimit {
// Nothing to delete, write the tail and return
rawdb.WriteReferenceIndexTail(bc.db, 0)
} else {
// Prune all stale reference indices and record the reference index tail
rawdb.UnindexReferences(bc.db, 0, head-bc.txLookupLimit+1, bc.quit)
}
return
}
// If a previous indexing existed, make sure that we fill in any missing entries
if bc.txLookupLimit == 0 || head < bc.txLookupLimit {
if *tail > 0 {
rawdb.IndexReferences(bc.db, 0, *tail, bc.quit)
}
return
}
// Update the reference index to the new chain state
if head-bc.txLookupLimit+1 < *tail {
// Reindex a part of missing indices and rewind index tail to HEAD-limit
rawdb.IndexReferences(bc.db, head-bc.txLookupLimit+1, *tail, bc.quit)
} else {
// Unindex a part of stale indices and forward index tail to HEAD-limit
rawdb.UnindexReferences(bc.db, *tail, head-bc.txLookupLimit+1, bc.quit)
}
}

// Any reindexing done, start listening to chain events and moving the index window
var (
done chan struct{} // Non-nil if background unindexing or reindexing routine is active.
headCh = make(chan ChainHeadEvent, 1) // Buffered to avoid locking up the event feed
)
sub := bc.SubscribeChainHeadEvent(headCh)
if sub == nil {
return
}
defer sub.Unsubscribe()

for {
select {
case head := <-headCh:
if done == nil {
done = make(chan struct{})
go indexBlocks(rawdb.ReadReferenceIndexTail(bc.db), head.Block.NumberU64(), done)
}
case <-done:
done = nil
case <-bc.quit:
if done != nil {
log.Info("Waiting background reference indexer to exit")
<-done
}
return
}
}
}

// reportBlock logs a bad block error.
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
rawdb.WriteBadBlock(bc.db, block)
Expand Down
Loading