Skip to content

Commit e50f64b

Browse files
authored
chore: add state field to bundlestore (#14)
1 parent 0a3c56d commit e50f64b

File tree

10 files changed

+128
-41
lines changed

10 files changed

+128
-41
lines changed

.sqlx/query-c279740d623e06b3e3add31a6c15085bde3207756fe914837cef0cd12b864366.json

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-ca6a250821d4542720578da20aa9cf31e808fa8dcbd701c75246dbdc95c58946.json

Lines changed: 0 additions & 23 deletions
This file was deleted.

crates/datastore/migrations/1757444171_create_bundles_table.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
1+
DO $$
2+
BEGIN
3+
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'bundle_state') THEN
4+
CREATE TYPE bundle_state AS ENUM (
5+
'Ready',
6+
'BundleLimit',
7+
'AccountLimits',
8+
'GlobalLimits',
9+
'IncludedInFlashblock',
10+
'IncludedInBlock'
11+
);
12+
END IF;
13+
END$$;
14+
15+
116
-- Create bundles table
217
CREATE TABLE IF NOT EXISTS bundles (
318
id UUID PRIMARY KEY,
19+
"state" bundle_state NOT NULL,
420

521
senders CHAR(42)[],
622
minimum_base_fee BIGINT, -- todo find a larger type

crates/datastore/src/postgres.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ use sqlx::PgPool;
1111
use tracing::info;
1212
use uuid::Uuid;
1313

14+
#[derive(Debug, Clone, sqlx::Type)]
15+
#[sqlx(type_name = "bundle_state", rename_all = "PascalCase")]
16+
pub enum BundleState {
17+
Ready,
18+
BundleLimit,
19+
AccountLimits,
20+
GlobalLimits,
21+
IncludedInFlashblock,
22+
IncludedInBlock,
23+
}
24+
1425
#[derive(sqlx::FromRow, Debug)]
1526
struct BundleRow {
1627
senders: Option<Vec<String>>,
@@ -22,6 +33,7 @@ struct BundleRow {
2233
block_number: Option<i64>,
2334
min_timestamp: Option<i64>,
2435
max_timestamp: Option<i64>,
36+
state: BundleState,
2537
}
2638

2739
/// Filter criteria for selecting bundles
@@ -60,6 +72,7 @@ pub struct BundleWithMetadata {
6072
pub txn_hashes: Vec<TxHash>,
6173
pub senders: Vec<Address>,
6274
pub min_base_fee: i64,
75+
pub state: BundleState,
6376
}
6477

6578
/// PostgreSQL implementation of the BundleDatastore trait
@@ -137,6 +150,7 @@ impl PostgresDatastore {
137150
txn_hashes: parsed_txn_hashes?,
138151
senders: parsed_senders?,
139152
min_base_fee: row.minimum_base_fee.unwrap_or(0),
153+
state: row.state,
140154
})
141155
}
142156

@@ -198,14 +212,15 @@ impl BundleDatastore for PostgresDatastore {
198212
sqlx::query!(
199213
r#"
200214
INSERT INTO bundles (
201-
id, senders, minimum_base_fee, txn_hashes,
215+
id, "state", senders, minimum_base_fee, txn_hashes,
202216
txs, reverting_tx_hashes, dropping_tx_hashes,
203217
block_number, min_timestamp, max_timestamp,
204218
created_at, updated_at
205219
)
206-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW(), NOW())
220+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, NOW(), NOW())
207221
"#,
208222
id,
223+
BundleState::Ready as BundleState,
209224
&senders,
210225
minimum_base_fee,
211226
&txn_hashes,
@@ -226,7 +241,7 @@ impl BundleDatastore for PostgresDatastore {
226241
let result = sqlx::query_as::<_, BundleRow>(
227242
r#"
228243
SELECT senders, minimum_base_fee, txn_hashes, txs, reverting_tx_hashes,
229-
dropping_tx_hashes, block_number, min_timestamp, max_timestamp
244+
dropping_tx_hashes, block_number, min_timestamp, max_timestamp, "state"
230245
FROM bundles
231246
WHERE id = $1
232247
"#,
@@ -266,7 +281,7 @@ impl BundleDatastore for PostgresDatastore {
266281
let rows = sqlx::query_as::<_, BundleRow>(
267282
r#"
268283
SELECT senders, minimum_base_fee, txn_hashes, txs, reverting_tx_hashes,
269-
dropping_tx_hashes, block_number, min_timestamp, max_timestamp
284+
dropping_tx_hashes, block_number, min_timestamp, max_timestamp, "state"
270285
FROM bundles
271286
WHERE minimum_base_fee >= $1
272287
AND (block_number = $2 OR block_number IS NULL OR block_number = 0 OR $2 = 0)

crates/datastore/tests/datastore.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use testcontainers_modules::{
55
postgres,
66
testcontainers::{ContainerAsync, runners::AsyncRunner},
77
};
8-
use tips_datastore::postgres::BundleFilter;
8+
use tips_datastore::postgres::{BundleFilter, BundleState};
99
use tips_datastore::{BundleDatastore, PostgresDatastore};
1010

1111
struct TestHarness {
@@ -96,6 +96,10 @@ async fn insert_and_get() -> eyre::Result<()> {
9696
let metadata = retrieved_bundle_with_metadata.unwrap();
9797
let retrieved_bundle = &metadata.bundle;
9898

99+
assert!(
100+
matches!(metadata.state, BundleState::Ready),
101+
"Bundle should default to Ready state"
102+
);
99103
assert_eq!(retrieved_bundle.txs.len(), test_bundle.txs.len());
100104
assert_eq!(retrieved_bundle.block_number, test_bundle.block_number);
101105
assert_eq!(retrieved_bundle.min_timestamp, test_bundle.min_timestamp);

justfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fix:
1414
cargo fmt --all
1515
cargo clippy --fix --allow-dirty --allow-staged
1616
# UI
17-
cd ui && npx biome check --fix
17+
cd ui && npx biome check --write --unsafe
1818

1919
create-migration name:
2020
touch crates/datastore/migrations/$(date +%s)_{{ name }}.sql
@@ -72,10 +72,10 @@ start-except programs: stop-all
7272

7373
### RUN SERVICES ###
7474
deps-reset:
75-
docker compose down && docker compose rm && rm -rf data/ && mkdir -p data/postgres data/kafka data/minio && docker compose up -d
75+
COMPOSE_FILE=docker-compose.yml:docker-compose.tips.yml docker compose down && docker compose rm && rm -rf data/ && mkdir -p data/postgres data/kafka data/minio && docker compose up -d
7676

7777
deps:
78-
docker compose down && docker compose rm && docker compose up -d
78+
COMPOSE_FILE=docker-compose.yml:docker-compose.tips.yml docker compose down && docker compose rm && docker compose up -d
7979

8080
audit:
8181
cargo run --bin tips-audit

ui/src/app/api/bundles/route.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import { bundles } from "@/db/schema";
44

55
export interface Bundle {
66
id: string;
7-
txnHashes: string[] | null;
7+
txnHashes: string[];
8+
state:
9+
| "Ready"
10+
| "BundleLimit"
11+
| "AccountLimits"
12+
| "GlobalLimits"
13+
| "IncludedInFlashblock"
14+
| "IncludedInBlock";
815
}
916

1017
export async function GET() {
@@ -13,6 +20,7 @@ export async function GET() {
1320
.select({
1421
id: bundles.id,
1522
txnHashes: bundles.txnHashes,
23+
state: bundles.state,
1624
})
1725
.from(bundles);
1826

ui/src/app/bundles/page.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,33 @@ export default function BundlesPage() {
8585
href={`/bundles/${bundle.id}`}
8686
className="block p-3 border rounded-lg bg-white/5 hover:bg-white/10 transition-colors"
8787
>
88-
<span className="font-mono text-sm">
89-
{bundle.id}
90-
{" ("}
91-
{bundle.txnHashes?.join(", ") || "No transactions"}
92-
{")"}
93-
</span>
88+
<div className="flex flex-col gap-1">
89+
<span className="font-mono text-sm">{bundle.id}</span>
90+
<div className="flex items-center gap-2 text-xs">
91+
<span
92+
className={`px-2 py-1 rounded font-medium ${
93+
bundle.state === "Ready"
94+
? "bg-blue-100 text-blue-600"
95+
: bundle.state === "BundleLimit"
96+
? "bg-yellow-100 text-yellow-600"
97+
: bundle.state === "AccountLimits"
98+
? "bg-orange-100 text-orange-600"
99+
: bundle.state === "GlobalLimits"
100+
? "bg-red-100 text-red-600"
101+
: bundle.state === "IncludedInFlashblock"
102+
? "bg-purple-100 text-purple-600"
103+
: bundle.state === "IncludedInBlock"
104+
? "bg-green-100 text-green-600"
105+
: "bg-gray-100 text-gray-600"
106+
}`}
107+
>
108+
{bundle.state}
109+
</span>
110+
<span className="text-gray-500">
111+
{bundle.txnHashes?.join(", ") || "No transactions"}
112+
</span>
113+
</div>
114+
</div>
94115
</Link>
95116
</li>
96117
))}

ui/src/db/relations.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
import { relations } from "drizzle-orm/relations";
2-
import {} from "./schema";

ui/src/db/schema.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
1-
import { sql } from "drizzle-orm";
21
import {
32
bigint,
43
char,
4+
pgEnum,
55
pgTable,
66
text,
77
timestamp,
88
uuid,
99
} from "drizzle-orm/pg-core";
1010

11+
export const bundleState = pgEnum("bundle_state", [
12+
"Ready",
13+
"BundleLimit",
14+
"AccountLimits",
15+
"GlobalLimits",
16+
"IncludedInFlashblock",
17+
"IncludedInBlock",
18+
]);
19+
1120
export const bundles = pgTable("bundles", {
1221
id: uuid().primaryKey().notNull(),
22+
state: bundleState().notNull(),
1323
senders: char({ length: 42 }).array(),
1424
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
1525
minimumBaseFee: bigint("minimum_base_fee", { mode: "number" }),

0 commit comments

Comments
 (0)