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

[action] add access list tx #4391

Merged
merged 2 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 31 additions & 0 deletions action/actctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package action

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -158,3 +159,33 @@ func (act *AbstractAction) fromProto(pb *iotextypes.ActionCore) error {
}
return nil
}

func (act *AbstractAction) convertToTx() TxCommonWithProto {
switch act.version {
case LegacyTxType:
tx := LegacyTx{
chainID: act.chainID,
nonce: act.nonce,
gasLimit: act.gasLimit,
gasPrice: &big.Int{},
}
if act.gasPrice != nil {
tx.gasPrice.Set(act.gasPrice)
}
return &tx
case AccessListTxType:
tx := AccessListTx{
chainID: act.chainID,
nonce: act.nonce,
gasLimit: act.gasLimit,
gasPrice: &big.Int{},
accessList: act.accessList,
}
if act.gasPrice != nil {
tx.gasPrice.Set(act.gasPrice)
}
return &tx
default:
panic(fmt.Sprintf("unsupported action version = %d", act.version))
}
}
7 changes: 7 additions & 0 deletions action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ import (
"github.com/pkg/errors"
)

const (
LegacyTxType = 1
AccessListTxType = 2
DynamicFeeTxType = 3
BlobTxType = 4
)

type (
// Action is the action can be Executed in protocols. The method is added to avoid mistakenly used empty interface as action.
Action interface {
Expand Down
37 changes: 20 additions & 17 deletions action/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,23 +79,24 @@ func (b *Builder) Build() AbstractAction {
// TODO: change envelope to *envelope
type EnvelopeBuilder struct {
elp envelope
ab AbstractAction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to keep the interface of EnvelopeBuilder as unchanged as possible to reduce modifications, it would be more suitable to change it to LegacyEnvelopeBuilder. The new EnvelopeBuilder may only need SetCommon() and SetPayload().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. the current builder is more intuitive and easier to understand/use: SetNonce().SetGasPrice().SetGasLimit()...
  2. SetCommon() and SetPayload() would cause too many code changes

}

// SetVersion sets action's version.
func (b *EnvelopeBuilder) SetVersion(v uint32) *EnvelopeBuilder {
b.elp.version = v
b.ab.version = v
return b
}

// SetNonce sets action's nonce.
func (b *EnvelopeBuilder) SetNonce(n uint64) *EnvelopeBuilder {
b.elp.nonce = n
b.ab.nonce = n
return b
}

// SetGasLimit sets action's gas limit.
func (b *EnvelopeBuilder) SetGasLimit(l uint64) *EnvelopeBuilder {
b.elp.gasLimit = l
b.ab.gasLimit = l
return b
}

Expand All @@ -104,8 +105,8 @@ func (b *EnvelopeBuilder) SetGasPrice(p *big.Int) *EnvelopeBuilder {
if p == nil {
return b
}
b.elp.gasPrice = &big.Int{}
b.elp.gasPrice.Set(p)
b.ab.gasPrice = &big.Int{}
b.ab.gasPrice.Set(p)
return b
}

Expand All @@ -114,8 +115,8 @@ func (b *EnvelopeBuilder) SetGasPriceByBytes(buf []byte) *EnvelopeBuilder {
if len(buf) == 0 {
return b
}
b.elp.gasPrice = &big.Int{}
b.elp.gasPrice.SetBytes(buf)
b.ab.gasPrice = &big.Int{}
b.ab.gasPrice.SetBytes(buf)
return b
}

Expand All @@ -127,12 +128,12 @@ func (b *EnvelopeBuilder) SetAction(action actionPayload) *EnvelopeBuilder {

// SetChainID sets action's chainID.
func (b *EnvelopeBuilder) SetChainID(chainID uint32) *EnvelopeBuilder {
b.elp.chainID = chainID
b.ab.chainID = chainID
return b
}

func (b *EnvelopeBuilder) SetAccessList(acl types.AccessList) *EnvelopeBuilder {
b.elp.accessList = acl
b.ab.accessList = acl
return b
}

Expand All @@ -142,15 +143,17 @@ func (b *EnvelopeBuilder) Build() Envelope {
}

func (b *EnvelopeBuilder) build() Envelope {
if b.elp.gasPrice == nil {
b.elp.gasPrice = big.NewInt(0)
if b.ab.gasPrice == nil {
b.ab.gasPrice = big.NewInt(0)
}
if b.elp.version == 0 {
b.elp.version = version.ProtocolVersion
if b.ab.version == 0 {
// default to version = 1 (legacy tx)
b.ab.version = LegacyTxType
}
if b.elp.payload == nil {
panic("cannot build Envelope w/o a valid payload")
}
b.elp.common = b.ab.convertToTx()
return &b.elp
}

Expand All @@ -165,10 +168,10 @@ func (b *EnvelopeBuilder) BuildTransfer(tx *types.Transaction) (Envelope, error)
}

func (b *EnvelopeBuilder) setEnvelopeCommonFields(tx *types.Transaction) {
b.elp.nonce = tx.Nonce()
b.elp.gasPrice = new(big.Int).Set(tx.GasPrice())
b.elp.gasLimit = tx.Gas()
b.elp.accessList = tx.AccessList()
b.ab.nonce = tx.Nonce()
b.ab.gasPrice = tx.GasPrice()
b.ab.gasLimit = tx.Gas()
b.ab.accessList = tx.AccessList()
}

func getRecipientAddr(addr *common.Address) string {
Expand Down
96 changes: 77 additions & 19 deletions action/envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package action

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -54,6 +55,17 @@ type (
TxBlob
}

TxCommonWithProto interface {
TxCommon
Version() uint32
ChainID() uint32
SanityCheck() error
toProto() *iotextypes.ActionCore
setNonce(uint64)
setGas(uint64)
setChainID(uint32)
}

TxDynamicGas interface {
GasTipCap() *big.Int
GasFeeCap() *big.Int
Expand All @@ -67,37 +79,57 @@ type (
}

envelope struct {
AbstractAction
common TxCommonWithProto
payload actionPayload
}
)

func (elp *envelope) Version() uint32 {
return elp.common.Version()
}

func (elp *envelope) ChainID() uint32 {
return elp.common.ChainID()
}

func (elp *envelope) Nonce() uint64 {
return elp.common.Nonce()
}

func (elp *envelope) Gas() uint64 {
return elp.gasLimit
return elp.common.Gas()
}

func (elp *envelope) GasPrice() *big.Int {
return elp.common.GasPrice()
}

func (elp *envelope) AccessList() types.AccessList {
return elp.accessList
return elp.common.AccessList()
}

func (elp *envelope) GasTipCap() *big.Int {
return elp.common.GasTipCap()
}

func (elp *envelope) GasFeeCap() *big.Int {
return elp.common.GasFeeCap()
}

func (elp *envelope) BlobGas() uint64 {
// TODO
return 0
return elp.common.BlobGas()
}

func (elp *envelope) BlobGasFeeCap() *big.Int {
// TODO
return nil
return elp.common.BlobGasFeeCap()
}

func (elp *envelope) BlobHashes() []common.Hash {
// TODO
return nil
return elp.common.BlobHashes()
}

func (elp *envelope) BlobTxSidecar() *types.BlobTxSidecar {
// TODO
return nil
return elp.common.BlobTxSidecar()
}

func (elp *envelope) Value() *big.Int {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not return common.Value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so far only EVM would use Value()

Expand Down Expand Up @@ -138,7 +170,7 @@ func (elp *envelope) Cost() (*big.Int, error) {
return nil, errors.Wrap(err, "failed to get payload's intrinsic gas")
}
if _, ok := elp.payload.(gasLimitForCost); ok {
gas = elp.Gas()
gas = elp.common.Gas()
}
if acl := elp.AccessList(); len(acl) > 0 {
gas += uint64(len(acl)) * TxAccessListAddressGas
Expand Down Expand Up @@ -169,7 +201,11 @@ func (elp *envelope) IntrinsicGas() (uint64, error) {

// Size returns the size of envelope
func (elp *envelope) Size() uint32 {
size := elp.BasicActionSize()
// VersionSizeInBytes + NonceSizeInBytes + GasSizeInBytes
var size uint32 = 4 + 8 + 8
if gasPrice := elp.common.GasPrice(); gasPrice != nil {
size += uint32(len(gasPrice.Bytes()))
}
if s, ok := elp.payload.(hasSize); ok {
size += s.Size()
}
Expand All @@ -187,15 +223,15 @@ func (elp *envelope) ToEthTx(evmNetworkID uint32, encoding iotextypes.Encoding)
// treat native tx as EVM LegacyTx
fallthrough
case encoding == iotextypes.Encoding_ETHEREUM_EIP155 || encoding == iotextypes.Encoding_ETHEREUM_UNPROTECTED:
return toLegacyTx(&elp.AbstractAction, elp.Action())
return toLegacyEthTx(elp.common, elp.Action())
default:
return nil, errors.Wrapf(ErrInvalidAct, "unsupported encoding type %v", encoding)
}
}

// Proto convert Envelope to protobuf format.
func (elp *envelope) Proto() *iotextypes.ActionCore {
actCore := elp.AbstractAction.toProto()
actCore := elp.common.toProto()

// TODO assert each action
switch act := elp.Action().(type) {
Expand Down Expand Up @@ -253,10 +289,26 @@ func (elp *envelope) LoadProto(pbAct *iotextypes.ActionCore) error {
if elp == nil {
return ErrNilAction
}
if err := elp.AbstractAction.fromProto(pbAct); err != nil {
if err := elp.loadProtoTxCommon(pbAct); err != nil {
return err
}
return elp.loadProtoActionPayload(pbAct)
}

func (elp *envelope) loadProtoTxCommon(pbAct *iotextypes.ActionCore) error {
var err error
switch pbAct.Version {
case LegacyTxType:
elp.common, err = fromProtoLegacyTx(pbAct)
case AccessListTxType:
elp.common, err = fromProtoAccessListTx(pbAct)
default:
panic(fmt.Sprintf("unsupported action version = %d", pbAct.Version))
}
return err
}

func (elp *envelope) loadProtoActionPayload(pbAct *iotextypes.ActionCore) error {
switch {
case pbAct.GetTransfer() != nil:
act := &Transfer{}
Expand Down Expand Up @@ -385,17 +437,23 @@ func (elp *envelope) LoadProto(pbAct *iotextypes.ActionCore) error {
return nil
}

func (elp *envelope) SetNonce(n uint64) {
elp.common.setNonce(n)
}

func (elp *envelope) SetGas(gas uint64) {
elp.SetGasLimit(gas)
elp.common.setGas(gas)
}

// SetChainID sets the chainID value
func (elp *envelope) SetChainID(chainID uint32) { elp.chainID = chainID }
func (elp *envelope) SetChainID(chainID uint32) {
elp.common.setChainID(chainID)
}

// SanityCheck does the sanity check
func (elp *envelope) SanityCheck() error {
if err := elp.payload.SanityCheck(); err != nil {
return err
}
return elp.AbstractAction.SanityCheck()
return elp.common.SanityCheck()
}
20 changes: 7 additions & 13 deletions action/envelope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,21 @@ func TestEnvelope_Proto(t *testing.T) {

proto := evlp.Proto()
actCore := &iotextypes.ActionCore{
Version: evlp.version,
Nonce: evlp.nonce,
GasLimit: evlp.gasLimit,
ChainID: evlp.chainID,
Version: evlp.Version(),
Nonce: evlp.Nonce(),
GasLimit: evlp.Gas(),
ChainID: evlp.ChainID(),
}
actCore.GasPrice = evlp.gasPrice.String()
actCore.GasPrice = evlp.GasPrice().String()
actCore.Action = &iotextypes.ActionCore_Transfer{Transfer: tsf.Proto()}
req.Equal(actCore, proto)

evlp2 := &envelope{}
req.NoError(evlp2.LoadProto(proto))
req.Equal(evlp.version, evlp2.version)
req.Equal(evlp.chainID, evlp2.chainID)
req.Equal(evlp.nonce, evlp2.nonce)
req.Equal(evlp.gasLimit, evlp2.gasLimit)
req.Equal(evlp.gasPrice, evlp2.gasPrice)
req.Equal(evlp, evlp2)
tsf2, ok := evlp2.Action().(*Transfer)
req.True(ok)
req.Equal(tsf.amount, tsf2.amount)
req.Equal(tsf.recipient, tsf2.recipient)
req.Equal(tsf.payload, tsf2.payload)
req.Equal(tsf, tsf2)
}

func TestEnvelope_Actions(t *testing.T) {
Expand Down
Loading
Loading