diff --git a/Cargo.lock b/Cargo.lock index f21f76a88..038dd78cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1676,6 +1676,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "doublezero_payment_tracker" +version = "0.3.0" +dependencies = [ + "async-trait", + "eyre", + "futures", + "http 1.3.1", + "mockall", + "reqwest", + "serde", + "serde_json", + "solana-client", + "solana-sdk", + "tokio", +] + [[package]] name = "doublezero_sdk" version = "0.3.0" diff --git a/smartcontract/sdk/go/serviceability/bytereader.go b/smartcontract/sdk/go/serviceability/bytereader.go index 179e6a025..27ae73a0a 100644 --- a/smartcontract/sdk/go/serviceability/bytereader.go +++ b/smartcontract/sdk/go/serviceability/bytereader.go @@ -99,6 +99,18 @@ func (br *ByteReader) ReadIPv4() [4]byte { return val } +func (br *ByteReader) ReadIPv4Slice() [][4]byte { + length := br.ReadU32() + if length == 0 || (length*4) > br.Remaining() { + return nil + } + result := make([][4]byte, length) + for i := uint32(0); i < length; i++ { + result[i] = br.ReadIPv4() + } + return result +} + func (br *ByteReader) ReadNetworkV4() [5]byte { if br.offset+5 > len(br.data) { return [5]byte{} diff --git a/smartcontract/sdk/go/serviceability/bytereader_test.go b/smartcontract/sdk/go/serviceability/bytereader_test.go index 0dc73c9c8..92e0d56af 100644 --- a/smartcontract/sdk/go/serviceability/bytereader_test.go +++ b/smartcontract/sdk/go/serviceability/bytereader_test.go @@ -184,6 +184,21 @@ func TestReadIPv4(t *testing.T) { } } +func TestReadIPv4Slice(t *testing.T) { + t.Parallel() + + data := []byte{0x02, 0x00, 0x00, 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9} + reader := NewByteReader(data) + val := reader.ReadIPv4Slice() + expected := [][4]byte{ + [4]byte{1, 2, 3, 4}, // nolint + [4]byte{5, 6, 7, 8}, // nolint + } + if !reflect.DeepEqual(val, expected) { + t.Errorf("ReadNetworkV4Slice returned incorrect value: got %#v, expected %#v", val, expected) + } +} + func TestReadNetworkV4(t *testing.T) { t.Parallel() diff --git a/smartcontract/sdk/go/serviceability/client_test.go b/smartcontract/sdk/go/serviceability/client_test.go index 933d39979..47576c752 100644 --- a/smartcontract/sdk/go/serviceability/client_test.go +++ b/smartcontract/sdk/go/serviceability/client_test.go @@ -39,8 +39,15 @@ var devicePayload = ` 483c031c496dd52ffd841907413a9259d8668196f939b255c27 4ee9fde636334e9df9b428bf14a9c4dbd07ca455b10aa67fbd9 0d17007ee2ad45706bd9a5a000b4579a7001080000007479322 -d647a303101000000b4579a701d903a23e92446591b0bb98794 -f3e278ae +d647a303101000000b4579a701d00020406080a0c0e10121416 +181a1c1e20222426282a2c2e30323436383a3c0000010203040 +5060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e +1fe8fd0000e9fd00000700000064656661756c7402000000080 +80808080804040200000081060f1c81060f1d02000000010b00 +0000737769746368312f312f3102002a000a0102031d7b00000 +1030000006c6f3001010f000a0203041d2a0001b245f92183e1 +b409bb7006560f858cf3bfa557c75cd967182a00392200b5de7 +8 ` var tunnelPayload = ` @@ -50,8 +57,10 @@ var tunnelPayload = ` f8198607689246e25c9403fba46e89122ff5d0fcc1febb51d4b 4ce64f17ad56c47b3d1d7f3f0100e40b5402000000282300008 0c3c9010000000080969800000000000500ac10000a1f011100 -00007479322d647a30313a6c61322d647a3031ad2570a0cf277 -61cab55a3f26d85fb20 +00007479322d647a30313a6c61322d647a30310001020304050 +60708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +0b000000737769746368312f312f31030000006c6f30ad2570a +0cf27761cab55a3f26d85fb20 ` var userPayload = ` @@ -193,18 +202,47 @@ func TestSDK_Serviceability_GetProgramData(t *testing.T) { Want: &ProgramData{ Devices: []Device{ { - AccountType: DeviceType, - Index: Uint128{High: 22, Low: 0}, - Bump_seed: 255, - Owner: getOwner(exchangePayload), - LocationPubKey: getPubKeyOffset(devicePayload, 50, 82), - ExchangePubKey: getPubKeyOffset(devicePayload, 82, 114), - DeviceType: 0, - PublicIp: [4]byte{0xb4, 0x57, 0x9a, 0x70}, - Status: 1, - Code: "ty2-dz01", - DzPrefixes: [][5]byte{{0xb4, 0x57, 0x9a, 0x70, 0x1d}}, - PubKey: pubkeys[2], + AccountType: DeviceType, + Index: Uint128{High: 22, Low: 0}, + Bump_seed: 255, + Owner: getOwner(exchangePayload), + LocationPubKey: getPubKeyOffset(devicePayload, 50, 82), + ExchangePubKey: getPubKeyOffset(devicePayload, 82, 114), + DeviceType: 0, + PublicIp: [4]byte{0xb4, 0x57, 0x9a, 0x70}, + Status: 1, + Code: "ty2-dz01", + DzPrefixes: [][5]byte{{0xb4, 0x57, 0x9a, 0x70, 0x1d}}, + MetricsPublisherPubKey: getPubKeyOffset(devicePayload, 141, 173), + ContributorPubKey: getPubKeyOffset(devicePayload, 173, 205), + BgpAsn: 65000, + DiaBgpAsn: 65001, + MgmtVrf: "default", + DnsServers: [][4]byte{{8, 8, 8, 8}, {8, 8, 4, 4}}, + NtpServers: [][4]byte{{129, 6, 15, 28}, {129, 6, 15, 29}}, + Interfaces: []Interface{ + { + Version: CurrentInterfaceVersion, + Name: "switch1/1/1", + InterfaceType: InterfaceTypePhysical, + LoopbackType: LoopbackTypeNone, + VlanId: 42, + IpNet: [5]byte{0x0a, 0x01, 0x02, 0x03, 0x1d}, + NodeSegmentIdx: 123, + UserTunnelEndpoint: false, + }, + { + Version: CurrentInterfaceVersion, + Name: "lo0", + InterfaceType: InterfaceTypeLoopback, + LoopbackType: LoopbackTypeVpnv4, + VlanId: 15, + IpNet: [5]byte{0x0a, 0x02, 0x03, 0x04, 0x1d}, + NodeSegmentIdx: 42, + UserTunnelEndpoint: true, + }, + }, + PubKey: pubkeys[2], }, }, Locations: []Location{}, @@ -279,22 +317,25 @@ func TestSDK_Serviceability_GetProgramData(t *testing.T) { Want: &ProgramData{ Links: []Link{ { - AccountType: LinkType, - Index: Uint128{High: 30, Low: 0}, - Bump_seed: 251, - Owner: getOwner(tunnelPayload), - SideAPubKey: getPubKeyOffset(tunnelPayload, 50, 82), - SideZPubKey: getPubKeyOffset(tunnelPayload, 82, 114), - LinkType: LinkLinkTypeMPLSoverGRE, - Bandwidth: 10000000000, - Mtu: 9000, - DelayNs: 30000000, - JitterNs: 10000000, - TunnelId: 5, - TunnelNet: [5]byte{0xac, 0x10, 0x00, 0x0a, 0x1f}, - Status: LinkStatusActivated, - Code: "ty2-dz01:la2-dz01", - PubKey: pubkeys[5], + AccountType: LinkType, + Index: Uint128{High: 30, Low: 0}, + Bump_seed: 251, + Owner: getOwner(tunnelPayload), + SideAPubKey: getPubKeyOffset(tunnelPayload, 50, 82), + SideZPubKey: getPubKeyOffset(tunnelPayload, 82, 114), + LinkType: LinkLinkTypeMPLSoverGRE, + Bandwidth: 10000000000, + Mtu: 9000, + DelayNs: 30000000, + JitterNs: 10000000, + TunnelId: 5, + TunnelNet: [5]byte{0xac, 0x10, 0x00, 0x0a, 0x1f}, + Status: LinkStatusActivated, + Code: "ty2-dz01:la2-dz01", + ContributorPubKey: [32]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, + SideAIfaceName: "switch1/1/1", + SideZIfaceName: "lo0", + PubKey: pubkeys[5], }, }, Locations: []Location{}, diff --git a/smartcontract/sdk/go/serviceability/deserialize.go b/smartcontract/sdk/go/serviceability/deserialize.go index f849c6889..2259838ba 100644 --- a/smartcontract/sdk/go/serviceability/deserialize.go +++ b/smartcontract/sdk/go/serviceability/deserialize.go @@ -1,5 +1,7 @@ package serviceability +import "log" + func DeserializeConfig(reader *ByteReader, cfg *Config) { cfg.AccountType = AccountType(reader.ReadU8()) cfg.Owner = reader.ReadPubkey() @@ -41,6 +43,17 @@ func DeserializeExchange(reader *ByteReader, exchange *Exchange) { exchange.PubKey = reader.ReadPubkey() } +func DeserializeInterface(reader *ByteReader, iface *Interface) { + iface.Version = reader.ReadU8() + iface.Name = reader.ReadString() + iface.InterfaceType = InterfaceType(reader.ReadU8()) + iface.LoopbackType = LoopbackType(reader.ReadU8()) + iface.VlanId = reader.ReadU16() + iface.IpNet = reader.ReadNetworkV4() + iface.NodeSegmentIdx = reader.ReadU16() + iface.UserTunnelEndpoint = (reader.ReadU8() != 0) +} + func DeserializeDevice(reader *ByteReader, dev *Device) { dev.AccountType = AccountType(reader.ReadU8()) dev.Owner = reader.ReadPubkey() @@ -54,6 +67,23 @@ func DeserializeDevice(reader *ByteReader, dev *Device) { dev.Code = reader.ReadString() dev.DzPrefixes = reader.ReadNetworkV4Slice() dev.MetricsPublisherPubKey = reader.ReadPubkey() + dev.ContributorPubKey = reader.ReadPubkey() + dev.BgpAsn = reader.ReadU32() + dev.DiaBgpAsn = reader.ReadU32() + dev.MgmtVrf = reader.ReadString() + dev.DnsServers = reader.ReadIPv4Slice() + dev.NtpServers = reader.ReadIPv4Slice() + dev.Interfaces = make([]Interface, 0) + var length = reader.ReadU32() + if (length * 18) > reader.Remaining() { + log.Println("DeserializeDevice: Not enough data for interfaces (# of interfaces = ", length, ")") + return + } + for i := uint32(0); i < length; i++ { + var iface Interface + DeserializeInterface(reader, &iface) + dev.Interfaces = append(dev.Interfaces, iface) + } dev.PubKey = reader.ReadPubkey() } @@ -73,6 +103,9 @@ func DeserializeLink(reader *ByteReader, link *Link) { link.TunnelNet = reader.ReadNetworkV4() link.Status = LinkStatus(reader.ReadU8()) link.Code = reader.ReadString() + link.ContributorPubKey = reader.ReadPubkey() + link.SideAIfaceName = reader.ReadString() + link.SideZIfaceName = reader.ReadString() link.PubKey = reader.ReadPubkey() } diff --git a/smartcontract/sdk/go/serviceability/state.go b/smartcontract/sdk/go/serviceability/state.go index 36415f242..f77e06f71 100644 --- a/smartcontract/sdk/go/serviceability/state.go +++ b/smartcontract/sdk/go/serviceability/state.go @@ -86,6 +86,37 @@ const ( DeviceStatusDeleted ) +type InterfaceType uint8 + +const ( + InterfaceTypeInvalid InterfaceType = iota + InterfaceTypeLoopback + InterfaceTypePhysical +) + +type LoopbackType uint8 + +const ( + LoopbackTypeNone LoopbackType = iota + LoopbackTypeVpnv4 + LoopbackTypeIpv4 + LoopbackTypePimRpAddr + LoopbackTypeReserved +) + +type Interface struct { + Version uint8 + Name string + InterfaceType InterfaceType + LoopbackType LoopbackType + VlanId uint16 + IpNet [5]uint8 + NodeSegmentIdx uint16 + UserTunnelEndpoint bool +} + +const CurrentInterfaceVersion = 1 + type Device struct { AccountType AccountType Owner [32]uint8 @@ -99,6 +130,13 @@ type Device struct { Code string DzPrefixes [][5]uint8 MetricsPublisherPubKey [32]uint8 + ContributorPubKey [32]byte + BgpAsn uint32 + DiaBgpAsn uint32 + MgmtVrf string + DnsServers [][4]uint8 + NtpServers [][4]uint8 + Interfaces []Interface PubKey [32]byte } @@ -118,22 +156,25 @@ const ( ) type Link struct { - AccountType AccountType - Owner [32]uint8 - Index Uint128 - Bump_seed uint8 - SideAPubKey [32]uint8 - SideZPubKey [32]uint8 - LinkType LinkLinkType - Bandwidth uint64 - Mtu uint32 - DelayNs uint64 - JitterNs uint64 - TunnelId uint16 - TunnelNet [5]uint8 - Status LinkStatus - Code string - PubKey [32]byte + AccountType AccountType + Owner [32]uint8 + Index Uint128 + Bump_seed uint8 + SideAPubKey [32]uint8 + SideZPubKey [32]uint8 + LinkType LinkLinkType + Bandwidth uint64 + Mtu uint32 + DelayNs uint64 + JitterNs uint64 + TunnelId uint16 + TunnelNet [5]uint8 + Status LinkStatus + Code string + ContributorPubKey [32]uint8 + SideAIfaceName string + SideZIfaceName string + PubKey [32]byte } type UserUserType uint8