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

feat: refactor request builder workflow #431

Merged
merged 13 commits into from
Apr 16, 2024

Conversation

leruaa
Copy link
Contributor

@leruaa leruaa commented Mar 30, 2024

Closes #423

Copy link
Member

@prestwich prestwich left a comment

Choose a reason for hiding this comment

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

good direction 🦺

crates/network/src/ethereum/builder.rs Outdated Show resolved Hide resolved
crates/network/src/ethereum/builder.rs Outdated Show resolved Hide resolved
crates/network/src/ethereum/builder.rs Outdated Show resolved Hide resolved
Copy link
Member

@prestwich prestwich left a comment

Choose a reason for hiding this comment

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

feature req:

/// Returns the transaction type that this builder will attempt to build. This does not imply 
/// that the builder is ready to build.
pub fn output_tx_type(&self) -> TxType

/// Returns the transaction type that this builder will build. `Err` if the builder
/// is not ready to build, containing the attempt type and missing/conflicted information
pub fn output_tx_type_checked(&self) -> Result<TxType, Vec<TransactionRequestError>>;

crates/network/src/ethereum/builder.rs Outdated Show resolved Hide resolved
crates/network/src/ethereum/builder.rs Outdated Show resolved Hide resolved
crates/network/src/transaction/builder.rs Outdated Show resolved Hide resolved
@@ -38,6 +39,44 @@ impl TransactionBuilderError {
}
}

/// Wrapper for [`InvalidTransactionRequestError`]s.
#[derive(Debug)]
pub struct InvalidTransactionRequestErrors(pub Vec<InvalidTransactionRequestError>);
Copy link
Member

Choose a reason for hiding this comment

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

it seems like this newtype is not adding any functionality, or preventing any common mistakes. It can be omitted, with the buildererror variant containing an unwrapped Vec

Copy link
Contributor Author

@leruaa leruaa Apr 1, 2024

Choose a reason for hiding this comment

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

Mmm It's for the Display impl, used on:

#[error("{0:?} transaction can't be built: {1}")]
InvalidTransactionRequest(TxType, InvalidTransactionRequestErrors),

Copy link
Member

Choose a reason for hiding this comment

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

let's manually impl that display?

}
}

fn will_build_2930(request: &TransactionRequest) -> Result<bool, TransactionBuilderError> {
Copy link
Member

Choose a reason for hiding this comment

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

these can be pub

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's also add some docs

@onbjerg onbjerg added the debt Tech debt which needs to be addressed label Apr 1, 2024
@leruaa leruaa requested a review from Evalir as a code owner April 1, 2024 20:25
@prestwich
Copy link
Member

the more i look at this the more complexity I see. e.g. a TransactionRequest may be valid for submission via send_transaction but not sufficiently filled to allow for signing via build

I may do some work on this 🤔

@leruaa
Copy link
Contributor Author

leruaa commented Apr 11, 2024

@prestwich Did you have time to have a look at this? Or maybe you can give pointers on the remaining work needed?

@prestwich
Copy link
Member

i'm still traveling for the next few days, so I don't have time to properly review :( I will be working on this and may take it over somewhat. sorry for taking so long and then stepping on your toes

@prestwich prestwich force-pushed the Improve_tx_request_builder branch from 23ead62 to 5b5e7c9 Compare April 12, 2024 13:20
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

this flow makes sense, but I worry the preferred type detection has unexpected results

how to enforce build will actually result in specific type?

I think form a builder pov, I'd also like to have something like

 builder().
   ....
   .ensure_type(ty: impl AsRef<u8>)?
   .build_preferred(, ty: impl AsRef<u8>)

Comment on lines +348 to +357
} else if self.access_list.is_some() {
TxType::Eip2930
} else if self.gas_price.is_some() {
TxType::Legacy
} else {
TxType::Eip1559
}
Copy link
Member

Choose a reason for hiding this comment

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

should 2930 only be if gas price is also set?

otherwise all txs with 1559 fee fields and an accesslist will be 2930

Copy link
Member

Choose a reason for hiding this comment

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

my basic design approach here is to prefer the MOST specific (LEAST common) thing set, to try to conform to user intent in most cases. So preference order is basically as follows:

  • Blobs are specific and critical to the tx, and have highest priority
  • Access lists are specific and (almost always) not critical
  • legacy gas is specific and never critical
  • eip1559 is the default case if no more-specific intention has been specified

otherwise all txs with 1559 fee fields and an accesslist will be 2930

this seems like correct behavior to me, because if the user specified an access list it is a more-specific intention than specifying 1559 gas

@@ -227,8 +230,24 @@ pub trait TransactionBuilder<N: Network>: Default + Sized + Send + Sync + 'stati
/// a valid transaction.
fn can_build(&self) -> bool;

/// Returns the transaction type that this builder will attempt to build.
/// This does not imply that the builder is ready to build.
fn output_tx_type(&self) -> TxType;
Copy link
Member

Choose a reason for hiding this comment

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

hmm, can we use the txtype in the trait here?

because txtypes are network specific

could operate on u8 or make txtype part of the network trait

Copy link
Member

Choose a reason for hiding this comment

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

good catch, we cannot.

could operate on u8 or make txtype part of the network trait

I am partial to the idea of using TxType on the network trait, but at that point, i would also want to incorporate into En/Decodable2718, and make something like trait En/Decodable2718<T: Into<u8> + TryFrom<u8, Error = _>> or similar so that we can enforce that the 2718 implementation uses the network TxType via a type TxEnvelope: Encodable2718<Self::TxType> bound

let me think about it a bit. most likely outcome is that this PR will operate on u8, and i will reserve network-assoc txtype for a later pr

Copy link
Member

@prestwich prestwich Apr 15, 2024

Choose a reason for hiding this comment

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

okay i made a network specific tx type because it felt right >.>

incorporating it into encodable/decodable can be later

@prestwich
Copy link
Member

this flow makes sense, but I worry the preferred type detection has unexpected results

how to enforce build will actually result in specific type?

I think form a builder pov, I'd also like to have something like

 builder().
   ....
   .ensure_type(ty: impl AsRef<u8>)?
   .build_preferred(, ty: impl AsRef<u8>)

@mattsse i've added the following. I copied the pattern from other builders, but i couldn't tell you which ones because it's beena minute since I saw them

 fn assert_preferred(&self, ty: N::TxType) -> Self {
    dbg_assert_eq!(self.preferred_type(), ty);
}

fn assert_preferred_chained(self, ty: N::TxType) -> Self { 
    self.assert_preferred(ty);
    self
}

@prestwich
Copy link
Member

prestwich commented Apr 15, 2024

@mattsse i failed to consider AnyTxType in the abstraction. will need to do some work there

ok done

@prestwich prestwich merged commit cb95183 into alloy-rs:main Apr 16, 2024
18 checks passed
ben186 pushed a commit to ben186/alloy that referenced this pull request Jul 27, 2024
* feat: refactor request builder workflow

* feat: return all tx builder errors in one invocation

* fix: avoid nesting

* feat: move get_invalid_*_fields() to TransactionRequest

* feat: Impl Display for TxType

* feat: (wip) get info about transaction type currently building

* wip: refactor refactor refactor

* feat: tx type in trait

* fix: core fmt

* fix: tests passing

* fix: no_std in consensus

* feature: assert_preferred

* fix: anytxtype

---------

Co-authored-by: James <[email protected]>
@leruaa leruaa deleted the Improve_tx_request_builder branch October 10, 2024 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
debt Tech debt which needs to be addressed
Projects
None yet
5 participants