diff --git a/activator/src/process/user.rs b/activator/src/process/user.rs index daa67f61b9..9ea977b076 100644 --- a/activator/src/process/user.rs +++ b/activator/src/process/user.rs @@ -1020,6 +1020,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -1227,6 +1230,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -1380,6 +1386,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -1497,6 +1506,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -1618,6 +1630,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -1730,6 +1745,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -1892,6 +1910,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::new(9, 9, 9, 9), tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Expect a reject transaction @@ -2010,6 +2031,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -2109,6 +2133,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = user.clone(); @@ -2286,6 +2313,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Deallocate — this should free the IP even though publishers is empty @@ -2339,6 +2369,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; deallocate_publisher_dz_ip(&ibrl_user, &mut publisher_dz_ips); @@ -2454,6 +2487,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: demanded_endpoint, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -2608,6 +2644,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::new(9, 9, 9, 9), tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Expect a reject transaction, NOT an activate @@ -2697,6 +2736,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, // no demand tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -2850,6 +2892,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: demanded_endpoint, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -3004,6 +3049,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::new(9, 9, 9, 9), tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Expect a reject transaction @@ -3115,6 +3163,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pk_unspecified, _) = get_accesspass_pda( @@ -3275,6 +3326,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // SDK's CloseAccountUserCommand fetches the user @@ -3395,6 +3449,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = user.clone(); diff --git a/activator/src/processor.rs b/activator/src/processor.rs index 21d115a30d..a43b736104 100644 --- a/activator/src/processor.rs +++ b/activator/src/processor.rs @@ -598,6 +598,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let mut users: HashMap = HashMap::new(); diff --git a/client/doublezero/src/command/connect.rs b/client/doublezero/src/command/connect.rs index cb5ea306bf..df78c19513 100644 --- a/client/doublezero/src/command/connect.rs +++ b/client/doublezero/src/command/connect.rs @@ -1436,6 +1436,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, } } diff --git a/client/doublezero/src/command/disconnect.rs b/client/doublezero/src/command/disconnect.rs index d58a17f99e..2dd27637bd 100644 --- a/client/doublezero/src/command/disconnect.rs +++ b/client/doublezero/src/command/disconnect.rs @@ -493,6 +493,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, } } diff --git a/controlplane/doublezero-admin/src/cli/device.rs b/controlplane/doublezero-admin/src/cli/device.rs index a022566f89..3db3f081b9 100644 --- a/controlplane/doublezero-admin/src/cli/device.rs +++ b/controlplane/doublezero-admin/src/cli/device.rs @@ -368,6 +368,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, } } diff --git a/sdk/serviceability/python/serviceability/state.py b/sdk/serviceability/python/serviceability/state.py index 705799db5f..1a61b961d9 100644 --- a/sdk/serviceability/python/serviceability/state.py +++ b/sdk/serviceability/python/serviceability/state.py @@ -337,6 +337,16 @@ def __str__(self) -> str: return _names.get(self.value, "unknown") +class BGPStatus(IntEnum): + UNKNOWN = 0 + UP = 1 + DOWN = 2 + + def __str__(self) -> str: + _names = {0: "unknown", 1: "up", 2: "down"} + return _names.get(self.value, "unknown") + + class MulticastGroupStatus(IntEnum): PENDING = 0 ACTIVATED = 1 @@ -716,6 +726,11 @@ class User: publishers: list[Pubkey] = field(default_factory=list) subscribers: list[Pubkey] = field(default_factory=list) validator_pub_key: Pubkey = Pubkey.default() + tunnel_endpoint: bytes = b"\x00" * 4 + tunnel_flags: int = 0 + bgp_status: BGPStatus = BGPStatus.UNKNOWN + last_bgp_up_at: int = 0 + last_bgp_reported_at: int = 0 @classmethod def from_bytes(cls, data: bytes) -> User: @@ -737,6 +752,11 @@ def from_bytes(cls, data: bytes) -> User: u.publishers = _read_pubkey_vec(r) u.subscribers = _read_pubkey_vec(r) u.validator_pub_key = _read_pubkey(r) + u.tunnel_endpoint = r.read_ipv4() + u.tunnel_flags = r.read_u8() + u.bgp_status = BGPStatus(r.read_u8()) + u.last_bgp_up_at = r.read_u64() + u.last_bgp_reported_at = r.read_u64() return u diff --git a/sdk/serviceability/python/serviceability/tests/test_fixtures.py b/sdk/serviceability/python/serviceability/tests/test_fixtures.py index 12401a8828..3ec3062e8b 100644 --- a/sdk/serviceability/python/serviceability/tests/test_fixtures.py +++ b/sdk/serviceability/python/serviceability/tests/test_fixtures.py @@ -7,6 +7,7 @@ from serviceability.state import ( AccessPass, + BGPStatus, Contributor, Device, Exchange, @@ -226,9 +227,23 @@ def test_deserialize(self): "TunnelId": u.tunnel_id, "Status": u.status, "ValidatorPubkey": u.validator_pub_key, + "TunnelFlags": u.tunnel_flags, + "BgpStatus": u.bgp_status, + "LastBgpUpAt": u.last_bgp_up_at, + "LastBgpReportedAt": u.last_bgp_reported_at, }, ) + def test_backward_compat_old_layout(self): + # Deserializing an account binary that predates bgp_status/last_bgp_up_at/last_bgp_reported_at + # must return zero values for those fields rather than failing. + data, _ = _load_fixture("user") + truncated = data[:-17] # remove bgp_status (1) + last_bgp_up_at (8) + last_bgp_reported_at (8) + u = User.from_bytes(truncated) + assert u.bgp_status == BGPStatus.UNKNOWN + assert u.last_bgp_up_at == 0 + assert u.last_bgp_reported_at == 0 + class TestFixtureMulticastGroup: def test_deserialize(self): diff --git a/sdk/serviceability/testdata/fixtures/generate-fixtures/Cargo.lock b/sdk/serviceability/testdata/fixtures/generate-fixtures/Cargo.lock index 0d9d791f9e..22c2004c19 100644 --- a/sdk/serviceability/testdata/fixtures/generate-fixtures/Cargo.lock +++ b/sdk/serviceability/testdata/fixtures/generate-fixtures/Cargo.lock @@ -346,7 +346,7 @@ dependencies = [ [[package]] name = "doublezero-program-common" -version = "0.12.0" +version = "0.16.0" dependencies = [ "borsh 1.6.0", "byteorder", @@ -358,7 +358,7 @@ dependencies = [ [[package]] name = "doublezero-serviceability" -version = "0.12.0" +version = "0.16.0" dependencies = [ "bitflags", "borsh 1.6.0", diff --git a/sdk/serviceability/testdata/fixtures/generate-fixtures/src/main.rs b/sdk/serviceability/testdata/fixtures/generate-fixtures/src/main.rs index 254c9f9ca0..78b1293eda 100644 --- a/sdk/serviceability/testdata/fixtures/generate-fixtures/src/main.rs +++ b/sdk/serviceability/testdata/fixtures/generate-fixtures/src/main.rs @@ -33,7 +33,7 @@ use doublezero_serviceability::state::{ multicastgroup::{MulticastGroup, MulticastGroupStatus}, programconfig::ProgramConfig, tenant::{Tenant, TenantBillingConfig, TenantPaymentStatus}, - user::{User, UserCYOA, UserStatus, UserType}, + user::{BGPStatus, User, UserCYOA, UserStatus, UserType}, }; use serde::Serialize; @@ -495,6 +495,9 @@ fn generate_user(dir: &Path) { validator_pubkey, tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: BGPStatus::Up, + last_bgp_up_at: 1_700_000_000, + last_bgp_reported_at: 1_700_000_100, }; let data = borsh::to_vec(&val).unwrap(); @@ -522,6 +525,10 @@ fn generate_user(dir: &Path) { FieldValue { name: "Subscribers0".into(), value: pubkey_bs58(&subscriber_pk), typ: "pubkey".into() }, FieldValue { name: "ValidatorPubkey".into(), value: pubkey_bs58(&validator_pubkey), typ: "pubkey".into() }, FieldValue { name: "TunnelEndpoint".into(), value: "0.0.0.0".into(), typ: "ipv4".into() }, + FieldValue { name: "TunnelFlags".into(), value: "0".into(), typ: "u8".into() }, + FieldValue { name: "BgpStatus".into(), value: "1".into(), typ: "u8".into() }, + FieldValue { name: "LastBgpUpAt".into(), value: "1700000000".into(), typ: "u64".into() }, + FieldValue { name: "LastBgpReportedAt".into(), value: "1700000100".into(), typ: "u64".into() }, ], }; diff --git a/sdk/serviceability/testdata/fixtures/user.bin b/sdk/serviceability/testdata/fixtures/user.bin index 49fadcd3b5..0668f896c6 100644 Binary files a/sdk/serviceability/testdata/fixtures/user.bin and b/sdk/serviceability/testdata/fixtures/user.bin differ diff --git a/sdk/serviceability/testdata/fixtures/user.json b/sdk/serviceability/testdata/fixtures/user.json index 0473ada0ab..426aa11c38 100644 --- a/sdk/serviceability/testdata/fixtures/user.json +++ b/sdk/serviceability/testdata/fixtures/user.json @@ -96,6 +96,26 @@ "name": "TunnelEndpoint", "value": "0.0.0.0", "typ": "ipv4" + }, + { + "name": "TunnelFlags", + "value": "0", + "typ": "u8" + }, + { + "name": "BgpStatus", + "value": "1", + "typ": "u8" + }, + { + "name": "LastBgpUpAt", + "value": "1700000000", + "typ": "u64" + }, + { + "name": "LastBgpReportedAt", + "value": "1700000100", + "typ": "u64" } ] -} \ No newline at end of file +} diff --git a/sdk/serviceability/typescript/serviceability/state.ts b/sdk/serviceability/typescript/serviceability/state.ts index d612b8dd56..d8ac7ffba1 100644 --- a/sdk/serviceability/typescript/serviceability/state.ts +++ b/sdk/serviceability/typescript/serviceability/state.ts @@ -246,6 +246,19 @@ export function userStatusString(v: number): string { return USER_STATUS_NAMES[v] ?? "unknown"; } +export const BGP_STATUS_UNKNOWN = 0; +export const BGP_STATUS_UP = 1; +export const BGP_STATUS_DOWN = 2; + +const BGP_STATUS_NAMES: Record = { + 0: "unknown", + 1: "up", + 2: "down", +}; +export function bgpStatusString(v: number): string { + return BGP_STATUS_NAMES[v] ?? "unknown"; +} + const MULTICAST_GROUP_STATUS_NAMES: Record = { 0: "pending", 1: "activated", @@ -709,6 +722,11 @@ export interface User { publishers: PublicKey[]; subscribers: PublicKey[]; validatorPubKey: PublicKey; + tunnelEndpoint: Uint8Array; + tunnelFlags: number; + bgpStatus: number; + lastBgpUpAt: bigint; + lastBgpReportedAt: bigint; } export function deserializeUser(data: Uint8Array): User { @@ -730,6 +748,11 @@ export function deserializeUser(data: Uint8Array): User { publishers: readPubkeyVec(r), subscribers: readPubkeyVec(r), validatorPubKey: readPubkey(r), + tunnelEndpoint: r.readIPv4(), + tunnelFlags: r.readU8(), + bgpStatus: r.readU8(), + lastBgpUpAt: r.readU64(), + lastBgpReportedAt: r.readU64(), }; } diff --git a/sdk/serviceability/typescript/serviceability/tests/fixtures.test.ts b/sdk/serviceability/typescript/serviceability/tests/fixtures.test.ts index baef305664..5b9ddcad39 100644 --- a/sdk/serviceability/typescript/serviceability/tests/fixtures.test.ts +++ b/sdk/serviceability/typescript/serviceability/tests/fixtures.test.ts @@ -263,8 +263,22 @@ describe("User fixture", () => { TunnelId: u.tunnelId, Status: u.status, ValidatorPubkey: u.validatorPubKey, + TunnelFlags: u.tunnelFlags, + BgpStatus: u.bgpStatus, + LastBgpUpAt: u.lastBgpUpAt, + LastBgpReportedAt: u.lastBgpReportedAt, }); }); + + test("backward compat: old layout yields zero for new fields", () => { + const [data] = loadFixture("user"); + // Remove bgp_status (1) + last_bgp_up_at (8) + last_bgp_reported_at (8) = 17 bytes + const truncated = data.slice(0, data.length - 17); + const u = deserializeUser(truncated); + expect(u.bgpStatus).toBe(0); + expect(u.lastBgpUpAt).toBe(0n); + expect(u.lastBgpReportedAt).toBe(0n); + }); }); describe("MulticastGroup fixture", () => { diff --git a/sdk/telemetry/testdata/fixtures/generate-fixtures/Cargo.lock b/sdk/telemetry/testdata/fixtures/generate-fixtures/Cargo.lock index 2352096a76..2255b8f0b8 100644 --- a/sdk/telemetry/testdata/fixtures/generate-fixtures/Cargo.lock +++ b/sdk/telemetry/testdata/fixtures/generate-fixtures/Cargo.lock @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "doublezero-config" -version = "0.10.0" +version = "0.16.0" dependencies = [ "eyre", "serde", @@ -591,7 +591,7 @@ dependencies = [ [[package]] name = "doublezero-program-common" -version = "0.10.0" +version = "0.16.0" dependencies = [ "borsh 1.6.0", "byteorder", @@ -603,7 +603,7 @@ dependencies = [ [[package]] name = "doublezero-serviceability" -version = "0.10.0" +version = "0.16.0" dependencies = [ "bitflags", "borsh 1.6.0", @@ -618,7 +618,7 @@ dependencies = [ [[package]] name = "doublezero-telemetry" -version = "0.10.0" +version = "0.16.0" dependencies = [ "borsh 1.6.0", "borsh-incremental", diff --git a/smartcontract/cli/src/multicastgroup/get.rs b/smartcontract/cli/src/multicastgroup/get.rs index e5ceff705f..2e86018a7d 100644 --- a/smartcontract/cli/src/multicastgroup/get.rs +++ b/smartcontract/cli/src/multicastgroup/get.rs @@ -342,6 +342,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let multicastgroup = MulticastGroup { diff --git a/smartcontract/cli/src/tenant/delete.rs b/smartcontract/cli/src/tenant/delete.rs index ffcab721ad..0c6ba955da 100644 --- a/smartcontract/cli/src/tenant/delete.rs +++ b/smartcontract/cli/src/tenant/delete.rs @@ -381,6 +381,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let tenant_after = Tenant { diff --git a/smartcontract/cli/src/user/delete.rs b/smartcontract/cli/src/user/delete.rs index 57bb2b124a..f625aa6b56 100644 --- a/smartcontract/cli/src/user/delete.rs +++ b/smartcontract/cli/src/user/delete.rs @@ -75,6 +75,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client diff --git a/smartcontract/cli/src/user/get.rs b/smartcontract/cli/src/user/get.rs index 0f7a05c046..790a266d73 100644 --- a/smartcontract/cli/src/user/get.rs +++ b/smartcontract/cli/src/user/get.rs @@ -247,6 +247,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = @@ -421,6 +424,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client diff --git a/smartcontract/cli/src/user/list.rs b/smartcontract/cli/src/user/list.rs index d1d01ba371..af5e4ddede 100644 --- a/smartcontract/cli/src/user/list.rs +++ b/smartcontract/cli/src/user/list.rs @@ -632,6 +632,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass1_pubkey, _) = @@ -671,6 +674,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass2_pubkey, _) = @@ -793,6 +799,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -814,6 +823,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -896,6 +908,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -917,6 +932,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -999,6 +1017,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1020,6 +1041,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -1102,6 +1126,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1123,6 +1150,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -1205,6 +1235,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1226,6 +1259,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -1323,6 +1359,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1344,6 +1383,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -1462,6 +1504,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1483,6 +1528,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { @@ -1631,6 +1679,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user2 = User { @@ -1652,6 +1703,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client.expect_list_user().returning(move |_| { diff --git a/smartcontract/cli/src/user/request_ban.rs b/smartcontract/cli/src/user/request_ban.rs index 344328e774..72261eaedc 100644 --- a/smartcontract/cli/src/user/request_ban.rs +++ b/smartcontract/cli/src/user/request_ban.rs @@ -80,6 +80,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client diff --git a/smartcontract/cli/src/user/subscribe.rs b/smartcontract/cli/src/user/subscribe.rs index 17cefc293e..1c8fb6c310 100644 --- a/smartcontract/cli/src/user/subscribe.rs +++ b/smartcontract/cli/src/user/subscribe.rs @@ -135,6 +135,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let mgroup_pubkey = Pubkey::from_str_const("11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo"); @@ -231,6 +234,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let mgroup_pubkey1 = Pubkey::from_str_const("11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo"); diff --git a/smartcontract/cli/src/user/update.rs b/smartcontract/cli/src/user/update.rs index 09c7fdcc04..6b2b21a605 100644 --- a/smartcontract/cli/src/user/update.rs +++ b/smartcontract/cli/src/user/update.rs @@ -102,6 +102,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client diff --git a/smartcontract/programs/doublezero-serviceability/src/processors/accesspass/set.rs b/smartcontract/programs/doublezero-serviceability/src/processors/accesspass/set.rs index 05c2a93511..17d3778220 100644 --- a/smartcontract/programs/doublezero-serviceability/src/processors/accesspass/set.rs +++ b/smartcontract/programs/doublezero-serviceability/src/processors/accesspass/set.rs @@ -28,7 +28,7 @@ use std::net::Ipv4Addr; // Value to rent exempt two `User` accounts + configurable amount for connect/disconnect txns // `User` account size assumes a single publisher and subscriber pubkey registered -const AIRDROP_USER_RENT_LAMPORTS_BYTES: usize = 241 * 3; // 241 bytes per User account x 3 accounts = 723 bytes +const AIRDROP_USER_RENT_LAMPORTS_BYTES: usize = 258 * 3; // 258 bytes per User account x 3 accounts = 774 bytes #[derive(BorshSerialize, BorshDeserializeIncremental, PartialEq, Clone)] pub struct SetAccessPassArgs { @@ -352,6 +352,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // User with 1 subscriber only (publisher use case) @@ -374,6 +377,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // User with both 1 publisher and 1 subscriber (future simultaneous pub/sub) @@ -396,6 +402,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let size_with_publisher = borsh::object_length(&user_with_publisher).unwrap(); @@ -403,25 +412,25 @@ mod tests { let size_with_both = borsh::object_length(&user_with_both).unwrap(); // Verify our understanding of the sizes - // Base User size (empty vecs) = 177 bytes (includes tunnel_flags u8) + // Base User size (empty vecs) = 194 bytes (includes tunnel_flags, bgp_status, last_bgp_up_at, last_bgp_reported_at) // Each Pubkey in publishers/subscribers adds 32 bytes assert_eq!( - size_with_publisher, 209, - "User with 1 publisher should be 209 bytes" + size_with_publisher, 226, + "User with 1 publisher should be 226 bytes" ); assert_eq!( - size_with_subscriber, 209, - "User with 1 subscriber should be 209 bytes" + size_with_subscriber, 226, + "User with 1 subscriber should be 226 bytes" ); assert_eq!( - size_with_both, 241, - "User with 1 publisher + 1 subscriber should be 241 bytes" + size_with_both, 258, + "User with 1 publisher + 1 subscriber should be 258 bytes" ); - // The constant should be sized for 3 accounts with both pub+sub (241 * 3 = 723) + // The constant should be sized for 3 accounts with both pub+sub (258 * 3 = 774) assert_eq!( AIRDROP_USER_RENT_LAMPORTS_BYTES, - 241 * 3, + 258 * 3, "AIRDROP_USER_RENT_LAMPORTS_BYTES should be sized for 3 User accounts with pub+sub" ); diff --git a/smartcontract/programs/doublezero-serviceability/src/processors/user/closeaccount.rs b/smartcontract/programs/doublezero-serviceability/src/processors/user/closeaccount.rs index f9e5ed7d6f..f5e743fa25 100644 --- a/smartcontract/programs/doublezero-serviceability/src/processors/user/closeaccount.rs +++ b/smartcontract/programs/doublezero-serviceability/src/processors/user/closeaccount.rs @@ -332,6 +332,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let device = Device { diff --git a/smartcontract/programs/doublezero-serviceability/src/processors/user/create_core.rs b/smartcontract/programs/doublezero-serviceability/src/processors/user/create_core.rs index 513ee58a3d..859a3d549b 100644 --- a/smartcontract/programs/doublezero-serviceability/src/processors/user/create_core.rs +++ b/smartcontract/programs/doublezero-serviceability/src/processors/user/create_core.rs @@ -352,6 +352,9 @@ pub fn create_user_core( } else { 0 }, + bgp_status: BGPStatus::Unknown, + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; Ok(CreateUserCoreResult { diff --git a/smartcontract/programs/doublezero-serviceability/src/state/user.rs b/smartcontract/programs/doublezero-serviceability/src/state/user.rs index 0d6b22faed..a2cac11fe7 100644 --- a/smartcontract/programs/doublezero-serviceability/src/state/user.rs +++ b/smartcontract/programs/doublezero-serviceability/src/state/user.rs @@ -249,6 +249,12 @@ pub struct User { pub tunnel_endpoint: Ipv4Addr, // 4 /// Bitflags recording durable tunnel properties. See [`TunnelFlags`]. pub tunnel_flags: u8, // 1 + /// BGP session status as last reported by the device agent. + pub bgp_status: BGPStatus, // 1 + /// Slot number of the most recent BGP session up event. + pub last_bgp_up_at: u64, // 8 + /// Slot number of the most recent BGP status report from the device agent. + pub last_bgp_reported_at: u64, // 8 } impl fmt::Display for User { @@ -297,6 +303,9 @@ impl TryFrom<&[u8]> for User { tunnel_endpoint: BorshDeserialize::deserialize(&mut data) .unwrap_or([0, 0, 0, 0].into()), tunnel_flags: BorshDeserialize::deserialize(&mut data).unwrap_or_default(), + bgp_status: BorshDeserialize::deserialize(&mut data).unwrap_or_default(), + last_bgp_up_at: BorshDeserialize::deserialize(&mut data).unwrap_or_default(), + last_bgp_reported_at: BorshDeserialize::deserialize(&mut data).unwrap_or_default(), }; if out.account_type != AccountType::User { @@ -505,6 +514,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let data = borsh::to_vec(&val).unwrap(); @@ -553,6 +565,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); @@ -581,6 +596,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -608,6 +626,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -635,6 +656,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -662,6 +686,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -689,6 +716,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -717,6 +747,9 @@ mod tests { validator_pubkey: Pubkey::new_unique(), tunnel_endpoint: Ipv4Addr::new(192, 168, 1, 1), // Private IP - invalid tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let err = val.validate(); assert!(err.is_err()); @@ -726,6 +759,9 @@ mod tests { let val_loopback = User { tunnel_endpoint: Ipv4Addr::new(127, 0, 0, 1), // Loopback - invalid tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, ..val.clone() }; let err = val_loopback.validate(); @@ -736,6 +772,9 @@ mod tests { let val_link_local = User { tunnel_endpoint: Ipv4Addr::new(169, 254, 1, 1), // Link-local - invalid tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, ..val.clone() }; let err = val_link_local.validate(); @@ -746,6 +785,9 @@ mod tests { let val_unspecified = User { tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, ..val.clone() }; assert!(val_unspecified.validate().is_ok()); @@ -754,6 +796,9 @@ mod tests { let val_global = User { tunnel_endpoint: Ipv4Addr::new(8, 8, 8, 8), // Global IP - valid tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, ..val }; assert!(val_global.validate().is_ok()); @@ -784,6 +829,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, } } @@ -923,6 +971,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::new(192, 168, 1, 1), // invalid: private IP tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; assert!(val.validate().is_ok()); @@ -977,15 +1028,32 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: TunnelFlags::CreatedAsPublisher as u8, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; - let mut data = borsh::to_vec(&user).unwrap(); - // Remove the last byte (tunnel_flags) to simulate an old account - data.pop(); - let deserialized = User::try_from(&data[..]).unwrap(); + let data = borsh::to_vec(&user).unwrap(); + // Remove tunnel_flags (1) + bgp_status (1) + last_bgp_up_at (8) + last_bgp_reported_at (8) + // to simulate an old account that predates tunnel_flags. + let old_data = &data[..data.len() - 18]; + let deserialized = User::try_from(old_data).unwrap(); assert_eq!( deserialized.tunnel_flags, 0, "Old accounts must default tunnel_flags to 0" ); + assert_eq!( + deserialized.bgp_status, + BGPStatus::Unknown, + "Old accounts must default bgp_status to Unknown" + ); + assert_eq!( + deserialized.last_bgp_up_at, 0, + "Old accounts must default last_bgp_up_at to 0" + ); + assert_eq!( + deserialized.last_bgp_reported_at, 0, + "Old accounts must default last_bgp_reported_at to 0" + ); } #[test] @@ -1009,6 +1077,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: TunnelFlags::CreatedAsPublisher as u8, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let data = borsh::to_vec(&user).unwrap(); let deserialized = User::try_from(&data[..]).unwrap(); diff --git a/smartcontract/sdk/go/serviceability/client_test.go b/smartcontract/sdk/go/serviceability/client_test.go index 1910cd06db..f52c338379 100644 --- a/smartcontract/sdk/go/serviceability/client_test.go +++ b/smartcontract/sdk/go/serviceability/client_test.go @@ -68,8 +68,8 @@ f14abe7ea3118ae1f000000000000000000000000000000fc00 000000000000000000000000000000000000000000000000000 0000000000000d2b30c6593b3dd99bbdde9c8e29eb9291adefb c11544a47f17d9472cae13fdfc010a0000010a000001f401a9f -e00001f010000000000000000fcef68d5d9eae991fd7d6284da -d2f2d7 +e00001f010000000000000000fcef68d5000000000000000000 +000000000000000000 ` var multicastgroupPayload = ` diff --git a/smartcontract/sdk/go/serviceability/deserialize.go b/smartcontract/sdk/go/serviceability/deserialize.go index 79ee26be2d..ed0ee87bfe 100644 --- a/smartcontract/sdk/go/serviceability/deserialize.go +++ b/smartcontract/sdk/go/serviceability/deserialize.go @@ -207,6 +207,10 @@ func DeserializeUser(reader *ByteReader, user *User) { user.Subscribers = reader.ReadPubkeySlice() user.ValidatorPubKey = reader.ReadPubkey() user.TunnelEndpoint = reader.ReadIPv4() + user.TunnelFlags = reader.ReadU8() + user.BgpStatus = reader.ReadU8() + user.LastBgpUpAt = reader.ReadU64() + user.LastBgpReportedAt = reader.ReadU64() // Note: user.PubKey is set separately in client.go after deserialization } diff --git a/smartcontract/sdk/go/serviceability/state.go b/smartcontract/sdk/go/serviceability/state.go index 3457a52eda..4329b3a852 100644 --- a/smartcontract/sdk/go/serviceability/state.go +++ b/smartcontract/sdk/go/serviceability/state.go @@ -913,8 +913,12 @@ type User struct { Subscribers [][32]uint8 ValidatorPubKey [32]uint8 // Tunnel endpoint IP (device-side GRE endpoint). 0.0.0.0 means use device.public_ip for backwards compatibility. - TunnelEndpoint [4]uint8 - PubKey [32]byte + TunnelEndpoint [4]uint8 + TunnelFlags uint8 + BgpStatus uint8 + LastBgpUpAt uint64 + LastBgpReportedAt uint64 + PubKey [32]byte } func (u User) MarshalJSON() ([]byte, error) { diff --git a/smartcontract/sdk/go/serviceability/state_test.go b/smartcontract/sdk/go/serviceability/state_test.go index 08675e8fc8..c69646ae3f 100644 --- a/smartcontract/sdk/go/serviceability/state_test.go +++ b/smartcontract/sdk/go/serviceability/state_test.go @@ -375,6 +375,10 @@ func TestCustomJSONMarshal(t *testing.T) { "Subscribers": ["` + dummyPubKeyB58 + `"], "ValidatorPubKey": "` + dummyPubKeyB58 + `", "TunnelEndpoint": "0.0.0.0", + "TunnelFlags": 0, + "BgpStatus": 0, + "LastBgpUpAt": 0, + "LastBgpReportedAt": 0, "PubKey": "` + dummyPubKeyB58 + `" }`, expectErr: false, diff --git a/smartcontract/sdk/rs/src/commands/multicastgroup/subscribe.rs b/smartcontract/sdk/rs/src/commands/multicastgroup/subscribe.rs index 3fc7e8c3ca..1979be6337 100644 --- a/smartcontract/sdk/rs/src/commands/multicastgroup/subscribe.rs +++ b/smartcontract/sdk/rs/src/commands/multicastgroup/subscribe.rs @@ -182,6 +182,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = get_accesspass_pda( @@ -324,6 +327,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = get_accesspass_pda(&program_id, &client_ip, &payer); diff --git a/smartcontract/sdk/rs/src/commands/tenant/delete.rs b/smartcontract/sdk/rs/src/commands/tenant/delete.rs index 83881419d9..f4580b0ae1 100644 --- a/smartcontract/sdk/rs/src/commands/tenant/delete.rs +++ b/smartcontract/sdk/rs/src/commands/tenant/delete.rs @@ -211,6 +211,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = get_accesspass_pda( diff --git a/smartcontract/sdk/rs/src/commands/user/activate.rs b/smartcontract/sdk/rs/src/commands/user/activate.rs index f029aed43d..d3b160c1dd 100644 --- a/smartcontract/sdk/rs/src/commands/user/activate.rs +++ b/smartcontract/sdk/rs/src/commands/user/activate.rs @@ -185,6 +185,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = get_accesspass_pda( @@ -279,6 +282,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (accesspass_pubkey, _) = get_accesspass_pda( diff --git a/smartcontract/sdk/rs/src/commands/user/closeaccount.rs b/smartcontract/sdk/rs/src/commands/user/closeaccount.rs index 40c78250c4..c2b9fce425 100644 --- a/smartcontract/sdk/rs/src/commands/user/closeaccount.rs +++ b/smartcontract/sdk/rs/src/commands/user/closeaccount.rs @@ -177,6 +177,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Mock User fetch @@ -240,6 +243,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // Compute ResourceExtension PDAs @@ -349,6 +355,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -413,6 +422,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let (global_resource_ext, _, _) = diff --git a/smartcontract/sdk/rs/src/commands/user/delete.rs b/smartcontract/sdk/rs/src/commands/user/delete.rs index 5d6d23356e..ca98b69d28 100644 --- a/smartcontract/sdk/rs/src/commands/user/delete.rs +++ b/smartcontract/sdk/rs/src/commands/user/delete.rs @@ -239,6 +239,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; // User with Updating status (returned by first retry call) @@ -446,6 +449,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user_updating = User { @@ -695,6 +701,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let user_activated_final = User { @@ -907,6 +916,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let owner = user.owner; diff --git a/smartcontract/sdk/rs/src/commands/user/requestban.rs b/smartcontract/sdk/rs/src/commands/user/requestban.rs index 115d641dbb..452a8794b3 100644 --- a/smartcontract/sdk/rs/src/commands/user/requestban.rs +++ b/smartcontract/sdk/rs/src/commands/user/requestban.rs @@ -229,6 +229,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client @@ -316,6 +319,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; let mut client = client; diff --git a/smartcontract/sdk/rs/src/commands/user/update.rs b/smartcontract/sdk/rs/src/commands/user/update.rs index 371ada5cfe..748fea9d8d 100644 --- a/smartcontract/sdk/rs/src/commands/user/update.rs +++ b/smartcontract/sdk/rs/src/commands/user/update.rs @@ -256,6 +256,9 @@ mod tests { validator_pubkey: Pubkey::default(), tunnel_endpoint: Ipv4Addr::UNSPECIFIED, tunnel_flags: 0, + bgp_status: Default::default(), + last_bgp_up_at: 0, + last_bgp_reported_at: 0, }; client diff --git a/smartcontract/sdk/rs/src/lib.rs b/smartcontract/sdk/rs/src/lib.rs index 682eeeaf46..904dfac968 100644 --- a/smartcontract/sdk/rs/src/lib.rs +++ b/smartcontract/sdk/rs/src/lib.rs @@ -30,7 +30,7 @@ pub use doublezero_serviceability::{ programconfig::ProgramConfig, resource_extension::ResourceExtensionOwned, tenant::Tenant, - user::{User, UserCYOA, UserStatus, UserType}, + user::{BGPStatus, User, UserCYOA, UserStatus, UserType}, }, };