Kick Contract (#2)
Production grade kick contract code for financial transaction tested for both vm and app modified schema to include node in kick, default time for deleted_app and removed unwanted fields app data migration for testing kick contract for active_app fixed some tests register operator Reviewed-on: #2 Co-authored-by: Noor <noormohammedb@protonmail.com> Co-committed-by: Noor <noormohammedb@protonmail.com> Signed-off-by: Noor <noormohammedb@protonmail.com>
This commit is contained in:
parent
198f43f472
commit
d1e85ec03e
569
saved_data.yaml
569
saved_data.yaml
@ -113,275 +113,328 @@ operators:
|
|||||||
email: first_on_detee@proton.me
|
email: first_on_detee@proton.me
|
||||||
banned_users: []
|
banned_users: []
|
||||||
vm_nodes:
|
vm_nodes:
|
||||||
- HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
|
- HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
|
||||||
- 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
- 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
||||||
- Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
- Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
||||||
- 4QbUXDM915RUFnHm3NiysLXFLk1WRGZvABwLNzx4tTEW
|
- 4QbUXDM915RUFnHm3NiysLXFLk1WRGZvABwLNzx4tTEW
|
||||||
- DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
- DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
||||||
app_nodes: []
|
app_nodes: []
|
||||||
x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
|
x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
|
||||||
escrow: 5499700480000
|
escrow: 5499700480000
|
||||||
email: gheo@detee.ltd
|
email: gheo@detee.ltd
|
||||||
banned_users: []
|
banned_users: []
|
||||||
vm_nodes:
|
vm_nodes:
|
||||||
- 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
|
- 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
|
||||||
- 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
- 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
||||||
app_nodes: []
|
app_nodes: []
|
||||||
7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB:
|
7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB:
|
||||||
escrow: 0
|
escrow: 888888888899999
|
||||||
email: ''
|
email: ""
|
||||||
banned_users: []
|
banned_users: []
|
||||||
vm_nodes: []
|
vm_nodes: []
|
||||||
app_nodes:
|
app_nodes:
|
||||||
- BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
|
- BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
|
||||||
vm_nodes:
|
vm_nodes:
|
||||||
- public_key: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
- public_key: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
||||||
operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
||||||
country: GB
|
country: GB
|
||||||
region: England
|
region: England
|
||||||
city: London
|
city: London
|
||||||
ip: 173.234.17.2
|
ip: 173.234.17.2
|
||||||
avail_mem_mb: 26000
|
avail_mem_mb: 26000
|
||||||
avail_vcpus: 28
|
avail_vcpus: 28
|
||||||
avail_storage_gbs: 680
|
avail_storage_gbs: 680
|
||||||
avail_ipv4: 2
|
avail_ipv4: 2
|
||||||
avail_ipv6: 65516
|
avail_ipv6: 65516
|
||||||
avail_ports: 19999
|
avail_ports: 19999
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 20000
|
price: 20000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
- public_key: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
- public_key: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
||||||
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
||||||
country: FR
|
country: FR
|
||||||
region: Île-de-France
|
region: Île-de-France
|
||||||
city: Paris
|
city: Paris
|
||||||
ip: 156.146.63.215
|
ip: 156.146.63.215
|
||||||
avail_mem_mb: 123000
|
avail_mem_mb: 123000
|
||||||
avail_vcpus: 46
|
avail_vcpus: 46
|
||||||
avail_storage_gbs: 440
|
avail_storage_gbs: 440
|
||||||
avail_ipv4: 2
|
avail_ipv4: 2
|
||||||
avail_ipv6: 0
|
avail_ipv6: 0
|
||||||
avail_ports: 20000
|
avail_ports: 20000
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 20000
|
price: 20000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
- public_key: 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
|
- public_key: 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
|
||||||
operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
||||||
country: CA
|
country: CA
|
||||||
region: Quebec
|
region: Quebec
|
||||||
city: Montréal
|
city: Montréal
|
||||||
ip: 184.107.169.199
|
ip: 184.107.169.199
|
||||||
avail_mem_mb: 30000
|
avail_mem_mb: 30000
|
||||||
avail_vcpus: 31
|
avail_vcpus: 31
|
||||||
avail_storage_gbs: 700
|
avail_storage_gbs: 700
|
||||||
avail_ipv4: 0
|
avail_ipv4: 0
|
||||||
avail_ipv6: 0
|
avail_ipv6: 0
|
||||||
avail_ports: 20000
|
avail_ports: 20000
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 18000
|
price: 18000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
- public_key: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
- public_key: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
||||||
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
||||||
country: CA
|
country: CA
|
||||||
region: British Columbia
|
region: British Columbia
|
||||||
city: Vancouver
|
city: Vancouver
|
||||||
ip: 149.22.95.1
|
ip: 149.22.95.1
|
||||||
avail_mem_mb: 109000
|
avail_mem_mb: 109000
|
||||||
avail_vcpus: 45
|
avail_vcpus: 45
|
||||||
avail_storage_gbs: 400
|
avail_storage_gbs: 400
|
||||||
avail_ipv4: 25
|
avail_ipv4: 25
|
||||||
avail_ipv6: 0
|
avail_ipv6: 0
|
||||||
avail_ports: 20000
|
avail_ports: 20000
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 20000
|
price: 20000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
- public_key: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
- public_key: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
||||||
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
||||||
country: US
|
country: US
|
||||||
region: California
|
region: California
|
||||||
city: San Jose
|
city: San Jose
|
||||||
ip: 149.36.48.99
|
ip: 149.36.48.99
|
||||||
avail_mem_mb: 120000
|
avail_mem_mb: 120000
|
||||||
avail_vcpus: 41
|
avail_vcpus: 41
|
||||||
avail_storage_gbs: 390
|
avail_storage_gbs: 390
|
||||||
avail_ipv4: 23
|
avail_ipv4: 23
|
||||||
avail_ipv6: 0
|
avail_ipv6: 0
|
||||||
avail_ports: 19999
|
avail_ports: 19999
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 20000
|
price: 20000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
- public_key: HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
|
- public_key: HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
|
||||||
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
|
||||||
country: CA
|
country: CA
|
||||||
region: British Columbia
|
region: British Columbia
|
||||||
city: Vancouver
|
city: Vancouver
|
||||||
ip: 149.22.95.28
|
ip: 149.22.95.28
|
||||||
avail_mem_mb: 125000
|
avail_mem_mb: 125000
|
||||||
avail_vcpus: 46
|
avail_vcpus: 46
|
||||||
avail_storage_gbs: 400
|
avail_storage_gbs: 400
|
||||||
avail_ipv4: 26
|
avail_ipv4: 26
|
||||||
avail_ipv6: 0
|
avail_ipv6: 0
|
||||||
avail_ports: 20000
|
avail_ports: 20000
|
||||||
max_ports_per_vm: 5
|
max_ports_per_vm: 5
|
||||||
price: 20000
|
price: 20000
|
||||||
reports: {}
|
reports: {}
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
vm_contracts:
|
vm_contracts:
|
||||||
- uuid: 958165e3-dea8-407d-8c42-dd17002ef79c
|
- uuid: 958165e3-dea8-407d-8c42-dd17002ef79c
|
||||||
hostname: detee-landing-fr
|
hostname: detee-landing-fr
|
||||||
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
||||||
node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 156.146.63.216
|
public_ipv4: 156.146.63.216
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 3000
|
memory_mb: 3000
|
||||||
kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
|
kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
|
||||||
dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
|
dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
|
||||||
created_at: 2025-02-28T23:19:41.769423466Z
|
created_at: 2025-02-28T23:19:41.769423466Z
|
||||||
updated_at: 2025-04-12T12:11:58.516768949Z
|
updated_at: 2025-04-12T12:11:58.516768949Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 14875500000
|
locked_nano: 14875500000
|
||||||
collected_at: 2025-04-20T00:34:15.461165181Z
|
collected_at: 2025-04-20T00:34:15.461165181Z
|
||||||
- uuid: e807a2fd-cf90-4a14-bc3a-89ce6dc59033
|
- uuid: e807a2fd-cf90-4a14-bc3a-89ce6dc59033
|
||||||
hostname: detee-landing-gb
|
hostname: detee-landing-gb
|
||||||
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
||||||
node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 173.234.136.154
|
public_ipv4: 173.234.136.154
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 3000
|
memory_mb: 3000
|
||||||
kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
|
kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
|
||||||
dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
|
dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
|
||||||
created_at: 2025-03-06T19:51:39.595163157Z
|
created_at: 2025-03-06T19:51:39.595163157Z
|
||||||
updated_at: 2025-03-06T19:51:39.595163842Z
|
updated_at: 2025-03-06T19:51:39.595163842Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 14875500000
|
locked_nano: 14875500000
|
||||||
collected_at: 2025-04-20T00:34:15.461181545Z
|
collected_at: 2025-04-20T00:34:15.461181545Z
|
||||||
- uuid: 23094406-2307-4332-a642-acee718d0186
|
- uuid: 23094406-2307-4332-a642-acee718d0186
|
||||||
hostname: heroic-door
|
hostname: heroic-door
|
||||||
admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
|
admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
|
||||||
node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
|
||||||
exposed_ports:
|
exposed_ports:
|
||||||
- 38288
|
- 38288
|
||||||
public_ipv4: ''
|
public_ipv4: ""
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 1
|
vcpus: 1
|
||||||
memory_mb: 1000
|
memory_mb: 1000
|
||||||
kernel_sha: 14e225e4aaf84cc2e0b5f64206121186ddebc4b378b886da3b2f7515dfd41692
|
kernel_sha: 14e225e4aaf84cc2e0b5f64206121186ddebc4b378b886da3b2f7515dfd41692
|
||||||
dtrfs_sha: 03ce24dbbe917fdd4f6347e61036805ddbdded5044c272bab188ef9333093bee
|
dtrfs_sha: 03ce24dbbe917fdd4f6347e61036805ddbdded5044c272bab188ef9333093bee
|
||||||
created_at: 2025-03-12T16:28:24.749161605Z
|
created_at: 2025-03-12T16:28:24.749161605Z
|
||||||
updated_at: 2025-03-12T16:28:24.749162477Z
|
updated_at: 2025-03-12T16:28:24.749162477Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 14134140000
|
locked_nano: 14134140000
|
||||||
collected_at: 2025-04-20T00:34:15.461191231Z
|
collected_at: 2025-04-20T00:34:15.461191231Z
|
||||||
- uuid: 1f49a71c-f68c-4c64-a82e-f50e0ba0b574
|
- uuid: 1f49a71c-f68c-4c64-a82e-f50e0ba0b574
|
||||||
hostname: astromech-wrench
|
hostname: astromech-wrench
|
||||||
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
||||||
node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 149.22.95.2
|
public_ipv4: 149.22.95.2
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 3000
|
memory_mb: 3000
|
||||||
kernel_sha: 3a68709138bed09c16671949cf1f03acee95a08381ba84fc70fb586001fa6767
|
kernel_sha: 3a68709138bed09c16671949cf1f03acee95a08381ba84fc70fb586001fa6767
|
||||||
dtrfs_sha: 0bb93443f65c9f4379ed469f94794f5c1bf14d8905b0b2c56a125df4a9ebe83e
|
dtrfs_sha: 0bb93443f65c9f4379ed469f94794f5c1bf14d8905b0b2c56a125df4a9ebe83e
|
||||||
created_at: 2025-03-20T14:40:25.557753393Z
|
created_at: 2025-03-20T14:40:25.557753393Z
|
||||||
updated_at: 2025-03-20T14:40:25.557754242Z
|
updated_at: 2025-03-20T14:40:25.557754242Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 11865620000
|
locked_nano: 11865620000
|
||||||
collected_at: 2025-04-20T00:34:15.461201690Z
|
collected_at: 2025-04-20T00:34:15.461201690Z
|
||||||
- uuid: 16577f1c-9867-4a17-80a8-6cf0490f1270
|
- uuid: 16577f1c-9867-4a17-80a8-6cf0490f1270
|
||||||
hostname: sofenty
|
hostname: sofenty
|
||||||
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
||||||
node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 156.146.63.217
|
public_ipv4: 156.146.63.217
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory_mb: 3000
|
memory_mb: 3000
|
||||||
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
||||||
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
||||||
created_at: 2025-04-07T22:57:57.646151746Z
|
created_at: 2025-04-07T22:57:57.646151746Z
|
||||||
updated_at: 2025-04-07T22:57:57.646152630Z
|
updated_at: 2025-04-07T22:57:57.646152630Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 11867500000
|
locked_nano: 11867500000
|
||||||
collected_at: 2025-04-20T00:34:15.461211040Z
|
collected_at: 2025-04-20T00:34:15.461211040Z
|
||||||
- uuid: 4b6e25ca-87ac-478b-8f16-aa8f5c44c704
|
- uuid: 4b6e25ca-87ac-478b-8f16-aa8f5c44c704
|
||||||
hostname: cloaked-mailbox
|
hostname: cloaked-mailbox
|
||||||
admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
|
admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
|
||||||
node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 149.22.95.2
|
public_ipv4: 149.22.95.2
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 30
|
disk_size_gb: 30
|
||||||
vcpus: 1
|
vcpus: 1
|
||||||
memory_mb: 1000
|
memory_mb: 1000
|
||||||
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
||||||
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
||||||
created_at: 2025-04-12T13:44:56.957037550Z
|
created_at: 2025-04-12T13:44:56.957037550Z
|
||||||
updated_at: 2025-04-12T13:44:56.957038546Z
|
updated_at: 2025-04-12T13:44:56.957038546Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 11177760000
|
locked_nano: 11177760000
|
||||||
collected_at: 2025-04-20T00:34:15.461219779Z
|
collected_at: 2025-04-20T00:34:15.461219779Z
|
||||||
- uuid: eb1a13ed-d782-4b71-8860-73540129cb7d
|
- uuid: eb1a13ed-d782-4b71-8860-73540129cb7d
|
||||||
hostname: twenty
|
hostname: twenty
|
||||||
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
|
||||||
node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
||||||
exposed_ports: []
|
exposed_ports: []
|
||||||
public_ipv4: 149.36.48.100
|
public_ipv4: 149.36.48.100
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 4
|
vcpus: 4
|
||||||
memory_mb: 4000
|
memory_mb: 4000
|
||||||
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
|
||||||
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
|
||||||
created_at: 2025-04-15T00:46:35.622165457Z
|
created_at: 2025-04-15T00:46:35.622165457Z
|
||||||
updated_at: 2025-04-15T00:46:35.622166372Z
|
updated_at: 2025-04-15T00:46:35.622166372Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 15570720000
|
locked_nano: 15570720000
|
||||||
collected_at: 2025-04-20T00:34:15.461230948Z
|
collected_at: 2025-04-20T00:34:15.461230948Z
|
||||||
- uuid: 1bf36309-3774-4825-b023-b2a0ef0405ed
|
- uuid: 1bf36309-3774-4825-b023-b2a0ef0405ed
|
||||||
hostname: shadowy-hobo
|
hostname: shadowy-hobo
|
||||||
admin_pubkey: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
admin_pubkey: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
|
||||||
node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
|
||||||
exposed_ports:
|
exposed_ports:
|
||||||
- 46393
|
- 46393
|
||||||
public_ipv4: ''
|
public_ipv4: ""
|
||||||
public_ipv6: ''
|
public_ipv6: ""
|
||||||
disk_size_gb: 10
|
disk_size_gb: 10
|
||||||
vcpus: 1
|
vcpus: 1
|
||||||
memory_mb: 1000
|
memory_mb: 1000
|
||||||
kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
|
kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
|
||||||
dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
|
dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
|
||||||
created_at: 2025-04-16T20:37:57.176592933Z
|
created_at: 2025-04-16T20:37:57.176592933Z
|
||||||
updated_at: 2025-04-16T20:37:57.176594069Z
|
updated_at: 2025-04-16T20:37:57.176594069Z
|
||||||
price_per_unit: 20000
|
price_per_unit: 20000
|
||||||
locked_nano: 12730960000
|
locked_nano: 12730960000
|
||||||
collected_at: 2025-04-20T00:34:15.461240342Z
|
collected_at: 2025-04-20T00:34:15.461240342Z
|
||||||
app_nodes:
|
app_nodes:
|
||||||
- node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
|
- node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
|
||||||
operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB
|
operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB
|
||||||
country: DE
|
country: DE
|
||||||
region: Hesse
|
region: Hesse
|
||||||
city: Frankfurt am Main
|
city: Frankfurt am Main
|
||||||
ip: 212.95.45.139
|
ip: 212.95.45.139
|
||||||
avail_mem_mb: 16000
|
avail_mem_mb: 16000
|
||||||
avail_vcpus: 16
|
avail_vcpus: 16
|
||||||
avail_storage_mb: 200000
|
avail_storage_mb: 200000
|
||||||
avail_no_of_port: 20000
|
avail_no_of_port: 20000
|
||||||
max_ports_per_app: 9
|
max_ports_per_app: 9
|
||||||
price: 20000
|
price: 20000
|
||||||
offline_minutes: 0
|
offline_minutes: 0
|
||||||
app_contracts: []
|
app_contracts:
|
||||||
|
- uuid: e3d01f25-2b2a-410b-80e3-12f44e474334
|
||||||
|
package_url: https://registry.detee.ltd/sgx/packages/base_package_2025-04-17_11-01-08.tar.gz
|
||||||
|
admin_pubkey: H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc
|
||||||
|
node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
|
||||||
|
mapped_ports:
|
||||||
|
- - 27158
|
||||||
|
- 34500
|
||||||
|
- - 28667
|
||||||
|
- 8080
|
||||||
|
host_ipv4: 212.95.45.139
|
||||||
|
disk_size_mb: 1000
|
||||||
|
vcpus: 1
|
||||||
|
memory_mb: 1000
|
||||||
|
created_at: 2025-04-21T11:27:28.833236909Z
|
||||||
|
updated_at: 2025-04-21T11:27:28.833237729Z
|
||||||
|
price_per_unit: 200000
|
||||||
|
locked_nano: 121200000
|
||||||
|
collected_at: 2025-04-21T11:28:24.905665571Z
|
||||||
|
hratls_pubkey: 7E0F887AA6BB9104EEC1066F454D4C2D9063D676715F55F919D3FBCEDC63240B
|
||||||
|
public_package_mr_enclave:
|
||||||
|
- 52
|
||||||
|
- 183
|
||||||
|
- 102
|
||||||
|
- 210
|
||||||
|
- 251
|
||||||
|
- 219
|
||||||
|
- 218
|
||||||
|
- 140
|
||||||
|
- 168
|
||||||
|
- 118
|
||||||
|
- 10
|
||||||
|
- 193
|
||||||
|
- 98
|
||||||
|
- 240
|
||||||
|
- 147
|
||||||
|
- 124
|
||||||
|
- 240
|
||||||
|
- 189
|
||||||
|
- 46
|
||||||
|
- 95
|
||||||
|
- 138
|
||||||
|
- 172
|
||||||
|
- 15
|
||||||
|
- 246
|
||||||
|
- 227
|
||||||
|
- 114
|
||||||
|
- 70
|
||||||
|
- 159
|
||||||
|
- 232
|
||||||
|
- 212
|
||||||
|
- 9
|
||||||
|
- 234
|
||||||
|
app_name: diligent-seahorse
|
||||||
|
@ -5,7 +5,7 @@ pub const CERT_PATH: &str = "/etc/detee/brain/brain-crt.pem";
|
|||||||
pub const CERT_KEY_PATH: &str = "/etc/detee/brain/brain-key.pem";
|
pub const CERT_KEY_PATH: &str = "/etc/detee/brain/brain-key.pem";
|
||||||
pub const CONFIG_PATH: &str = "/etc/detee/brain/config.ini";
|
pub const CONFIG_PATH: &str = "/etc/detee/brain/config.ini";
|
||||||
|
|
||||||
pub const DB_SCHEMA_FILE: &str = "interim_tables.surql";
|
pub const DB_SCHEMA_FILES: [&str; 2] = ["surql/tables.sql", "surql/functions.sql"];
|
||||||
|
|
||||||
pub static ADMIN_ACCOUNTS: LazyLock<Vec<String>> = LazyLock::new(|| {
|
pub static ADMIN_ACCOUNTS: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||||
let default_admin_keys = vec![
|
let default_admin_keys = vec![
|
||||||
@ -23,6 +23,8 @@ pub static ADMIN_ACCOUNTS: LazyLock<Vec<String>> = LazyLock::new(|| {
|
|||||||
pub const OLD_BRAIN_DATA_PATH: &str = "./saved_data.yaml";
|
pub const OLD_BRAIN_DATA_PATH: &str = "./saved_data.yaml";
|
||||||
|
|
||||||
pub const ACCOUNT: &str = "account";
|
pub const ACCOUNT: &str = "account";
|
||||||
|
pub const KICK: &str = "kick";
|
||||||
|
|
||||||
pub const VM_NODE: &str = "vm_node";
|
pub const VM_NODE: &str = "vm_node";
|
||||||
pub const ACTIVE_VM: &str = "active_vm";
|
pub const ACTIVE_VM: &str = "active_vm";
|
||||||
pub const VM_UPDATE_EVENT: &str = "vm_update_event";
|
pub const VM_UPDATE_EVENT: &str = "vm_update_event";
|
||||||
@ -42,3 +44,6 @@ pub const ID_ALPHABET: [char; 62] = [
|
|||||||
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||||
'V', 'W', 'X', 'Y', 'Z',
|
'V', 'W', 'X', 'Y', 'Z',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const MIN_ESCROW: u64 = 5000;
|
||||||
|
pub const TOKEN_DECIMAL: u64 = 1_000_000_000;
|
||||||
|
126
src/db/app.rs
126
src/db/app.rs
@ -12,7 +12,7 @@ use surrealdb::sql::Datetime;
|
|||||||
use surrealdb::{Notification, RecordId, Surreal};
|
use surrealdb::{Notification, RecordId, Surreal};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct AppNode {
|
pub struct AppNode {
|
||||||
pub id: RecordId,
|
pub id: RecordId,
|
||||||
pub operator: RecordId,
|
pub operator: RecordId,
|
||||||
@ -32,8 +32,9 @@ pub struct AppNode {
|
|||||||
impl AppNode {
|
impl AppNode {
|
||||||
pub async fn register(self, db: &Surreal<Client>) -> Result<AppNode, Error> {
|
pub async fn register(self, db: &Surreal<Client>) -> Result<AppNode, Error> {
|
||||||
db::Account::get_or_create(db, &self.operator.key().to_string()).await?;
|
db::Account::get_or_create(db, &self.operator.key().to_string()).await?;
|
||||||
let app_node: Option<AppNode> = db.upsert(self.id.clone()).content(self).await?;
|
let app_node_id = self.id.clone();
|
||||||
app_node.ok_or(Error::FailedToCreateDBEntry)
|
let app_node: Option<AppNode> = db.upsert(app_node_id.clone()).content(self).await?;
|
||||||
|
app_node.ok_or(Error::FailedToCreateDBEntry(format!("{APP_NODE}:{app_node_id}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ impl From<DeletedApp> for AppDaemonMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct NewAppReq {
|
pub struct NewAppReq {
|
||||||
pub id: RecordId,
|
pub id: RecordId,
|
||||||
#[serde(rename = "in")]
|
#[serde(rename = "in")]
|
||||||
@ -97,6 +98,7 @@ impl NewAppReq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn submit(self, db: &Surreal<Client>) -> Result<Vec<Self>, Error> {
|
pub async fn submit(self, db: &Surreal<Client>) -> Result<Vec<Self>, Error> {
|
||||||
|
// TODO: handle financial transaction
|
||||||
let new_app_req: Vec<Self> = db.insert(NEW_APP_REQ).relation(self).await?;
|
let new_app_req: Vec<Self> = db.insert(NEW_APP_REQ).relation(self).await?;
|
||||||
Ok(new_app_req)
|
Ok(new_app_req)
|
||||||
}
|
}
|
||||||
@ -164,7 +166,7 @@ impl AppNodeWithReports {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ActiveApp {
|
pub struct ActiveApp {
|
||||||
pub id: RecordId,
|
pub id: RecordId,
|
||||||
#[serde(rename = "in")]
|
#[serde(rename = "in")]
|
||||||
@ -172,11 +174,11 @@ pub struct ActiveApp {
|
|||||||
#[serde(rename = "out")]
|
#[serde(rename = "out")]
|
||||||
pub app_node: RecordId,
|
pub app_node: RecordId,
|
||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
pub mapped_ports: Vec<(u64, u64)>,
|
pub mapped_ports: Vec<(u32, u32)>,
|
||||||
pub host_ipv4: String,
|
pub host_ipv4: String,
|
||||||
pub vcpus: u64,
|
pub vcpus: u32,
|
||||||
pub memory_mb: u64,
|
pub memory_mb: u32,
|
||||||
pub disk_size_gb: u64,
|
pub disk_size_gb: u32,
|
||||||
pub created_at: Datetime,
|
pub created_at: Datetime,
|
||||||
pub price_per_unit: u64,
|
pub price_per_unit: u64,
|
||||||
pub locked_nano: u64,
|
pub locked_nano: u64,
|
||||||
@ -210,6 +212,15 @@ impl From<ActiveApp> for DeletedApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ActiveApp {
|
impl ActiveApp {
|
||||||
|
pub fn price_per_minute(&self) -> u64 {
|
||||||
|
(self.total_units() * self.price_per_unit as f64) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_units(&self) -> f64 {
|
||||||
|
// TODO: Optimize this based on price of hardware.
|
||||||
|
(self.vcpus as f64 * 5f64) + (self.memory_mb as f64 / 200f64) + (self.disk_size_gb as f64)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn activate(db: &Surreal<Client>, id: &str) -> Result<(), Error> {
|
pub async fn activate(db: &Surreal<Client>, id: &str) -> Result<(), Error> {
|
||||||
let new_app_req = match NewAppReq::get(db, id).await? {
|
let new_app_req = match NewAppReq::get(db, id).await? {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
@ -223,9 +234,9 @@ impl ActiveApp {
|
|||||||
app_name: new_app_req.app_name,
|
app_name: new_app_req.app_name,
|
||||||
mapped_ports: vec![],
|
mapped_ports: vec![],
|
||||||
host_ipv4: String::new(),
|
host_ipv4: String::new(),
|
||||||
vcpus: new_app_req.vcpu as u64,
|
vcpus: new_app_req.vcpu,
|
||||||
memory_mb: new_app_req.memory_mb as u64,
|
memory_mb: new_app_req.memory_mb,
|
||||||
disk_size_gb: new_app_req.disk_mb as u64,
|
disk_size_gb: new_app_req.disk_mb,
|
||||||
created_at: new_app_req.created_at.clone(),
|
created_at: new_app_req.created_at.clone(),
|
||||||
price_per_unit: new_app_req.price_per_unit,
|
price_per_unit: new_app_req.price_per_unit,
|
||||||
locked_nano: new_app_req.locked_nano,
|
locked_nano: new_app_req.locked_nano,
|
||||||
@ -293,7 +304,7 @@ impl ActiveApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ActiveAppWithNode {
|
pub struct ActiveAppWithNode {
|
||||||
pub id: RecordId,
|
pub id: RecordId,
|
||||||
#[serde(rename = "in")]
|
#[serde(rename = "in")]
|
||||||
@ -301,11 +312,11 @@ pub struct ActiveAppWithNode {
|
|||||||
#[serde(rename = "out")]
|
#[serde(rename = "out")]
|
||||||
pub app_node: AppNode,
|
pub app_node: AppNode,
|
||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
pub mapped_ports: Vec<(u64, u64)>,
|
pub mapped_ports: Vec<(u32, u32)>,
|
||||||
pub host_ipv4: String,
|
pub host_ipv4: String,
|
||||||
pub vcpus: u64,
|
pub vcpus: u32,
|
||||||
pub memory_mb: u64,
|
pub memory_mb: u32,
|
||||||
pub disk_size_gb: u64,
|
pub disk_size_gb: u32,
|
||||||
pub created_at: Datetime,
|
pub created_at: Datetime,
|
||||||
pub price_per_unit: u64,
|
pub price_per_unit: u64,
|
||||||
pub locked_nano: u64,
|
pub locked_nano: u64,
|
||||||
@ -315,10 +326,37 @@ pub struct ActiveAppWithNode {
|
|||||||
pub hratls_pubkey: String,
|
pub hratls_pubkey: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ActiveAppWithNode> for ActiveApp {
|
||||||
|
fn from(val: ActiveAppWithNode) -> Self {
|
||||||
|
Self {
|
||||||
|
id: val.id,
|
||||||
|
admin: val.admin,
|
||||||
|
app_node: val.app_node.id,
|
||||||
|
app_name: val.app_name,
|
||||||
|
mapped_ports: val.mapped_ports,
|
||||||
|
host_ipv4: val.host_ipv4,
|
||||||
|
vcpus: val.vcpus,
|
||||||
|
memory_mb: val.memory_mb,
|
||||||
|
disk_size_gb: val.disk_size_gb,
|
||||||
|
created_at: val.created_at,
|
||||||
|
price_per_unit: val.price_per_unit,
|
||||||
|
locked_nano: val.locked_nano,
|
||||||
|
collected_at: val.collected_at,
|
||||||
|
mr_enclave: val.mr_enclave,
|
||||||
|
package_url: val.package_url,
|
||||||
|
hratls_pubkey: val.hratls_pubkey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveAppWithNode {
|
impl ActiveAppWithNode {
|
||||||
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
|
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
|
||||||
let contract: Option<Self> =
|
let contract: Option<Self> = db
|
||||||
db.query(format!("select * from {ACTIVE_APP}:{uuid} fetch out;")).await?.take(0)?;
|
.query(format!("select * from {ACTIVE_APP} where id = $uuid_input fetch out;"))
|
||||||
|
.bind(("uuid_input", RecordId::from((ACTIVE_APP, uuid))))
|
||||||
|
.await?
|
||||||
|
.take(0)?;
|
||||||
|
|
||||||
Ok(contract)
|
Ok(contract)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +431,7 @@ impl From<&old_brain::BrainData> for Vec<AppNode> {
|
|||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
for old_node in old_data.app_nodes.iter() {
|
for old_node in old_data.app_nodes.iter() {
|
||||||
nodes.push(AppNode {
|
nodes.push(AppNode {
|
||||||
id: RecordId::from(("app_node", old_node.node_pubkey.clone())),
|
id: RecordId::from((APP_NODE, old_node.node_pubkey.clone())),
|
||||||
operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
|
operator: RecordId::from((ACCOUNT, old_node.operator_wallet.clone())),
|
||||||
country: old_node.country.clone(),
|
country: old_node.country.clone(),
|
||||||
region: old_node.region.clone(),
|
region: old_node.region.clone(),
|
||||||
@ -412,6 +450,46 @@ impl From<&old_brain::BrainData> for Vec<AppNode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&old_brain::BrainData> for Vec<ActiveApp> {
|
||||||
|
fn from(old_data: &old_brain::BrainData) -> Self {
|
||||||
|
let mut contracts = Vec::new();
|
||||||
|
for old_c in old_data.app_contracts.iter() {
|
||||||
|
let mut mapped_ports = Vec::new();
|
||||||
|
for port in old_c.mapped_ports.clone().into_iter().map(|(b, c)| (b as u32, c as u32)) {
|
||||||
|
mapped_ports.push(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mr_enclave_hex = old_c
|
||||||
|
.public_package_mr_enclave
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.iter()
|
||||||
|
.map(|byte| format!("{byte:02X}"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
contracts.push(ActiveApp {
|
||||||
|
id: RecordId::from((ACTIVE_APP, old_c.uuid.replace("-", ""))),
|
||||||
|
admin: RecordId::from((ACCOUNT, old_c.admin_pubkey.clone())),
|
||||||
|
app_node: RecordId::from((APP_NODE, old_c.node_pubkey.clone())),
|
||||||
|
mapped_ports,
|
||||||
|
host_ipv4: old_c.host_ipv4.clone(),
|
||||||
|
disk_size_gb: old_c.disk_size_mb * 1024,
|
||||||
|
vcpus: old_c.vcpus,
|
||||||
|
memory_mb: old_c.memory_mb,
|
||||||
|
price_per_unit: old_c.price_per_unit,
|
||||||
|
locked_nano: old_c.locked_nano,
|
||||||
|
created_at: old_c.created_at.into(),
|
||||||
|
collected_at: old_c.collected_at.into(),
|
||||||
|
app_name: old_c.app_name.clone(),
|
||||||
|
mr_enclave: mr_enclave_hex,
|
||||||
|
package_url: old_c.package_url.clone(),
|
||||||
|
hratls_pubkey: old_c.hratls_pubkey.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
contracts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct DeletedApp {
|
pub struct DeletedApp {
|
||||||
pub id: RecordId,
|
pub id: RecordId,
|
||||||
@ -420,11 +498,11 @@ pub struct DeletedApp {
|
|||||||
#[serde(rename = "out")]
|
#[serde(rename = "out")]
|
||||||
pub app_node: RecordId,
|
pub app_node: RecordId,
|
||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
pub mapped_ports: Vec<(u64, u64)>,
|
pub mapped_ports: Vec<(u32, u32)>,
|
||||||
pub host_ipv4: String,
|
pub host_ipv4: String,
|
||||||
pub vcpus: u64,
|
pub vcpus: u32,
|
||||||
pub memory_mb: u64,
|
pub memory_mb: u32,
|
||||||
pub disk_size_gb: u64,
|
pub disk_size_gb: u32,
|
||||||
pub created_at: Datetime,
|
pub created_at: Datetime,
|
||||||
pub price_per_unit: u64,
|
pub price_per_unit: u64,
|
||||||
pub locked_nano: u64,
|
pub locked_nano: u64,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::constants::ACCOUNT;
|
|
||||||
use crate::db::prelude::*;
|
|
||||||
|
|
||||||
use super::Error;
|
use super::Error;
|
||||||
|
use crate::constants::{ACCOUNT, KICK, MIN_ESCROW, TOKEN_DECIMAL};
|
||||||
|
use crate::db::prelude::*;
|
||||||
use crate::old_brain;
|
use crate::old_brain;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::engine::remote::ws::Client;
|
use surrealdb::engine::remote::ws::Client;
|
||||||
@ -37,7 +36,7 @@ impl Account {
|
|||||||
Some(account) => Ok(account),
|
Some(account) => Ok(account),
|
||||||
None => {
|
None => {
|
||||||
let account: Option<Self> = db.create(id).await?;
|
let account: Option<Self> = db.create(id).await?;
|
||||||
account.ok_or(Error::FailedToCreateDBEntry)
|
account.ok_or(Error::FailedToCreateDBEntry(ACCOUNT.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +48,33 @@ impl Account {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn save(self, db: &Surreal<Client>) -> Result<Option<Self>, Error> {
|
||||||
|
let account: Option<Self> = db.upsert(self.id.clone()).content(self).await?;
|
||||||
|
Ok(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn operator_reg(
|
||||||
|
db: &Surreal<Client>,
|
||||||
|
wallet: &str,
|
||||||
|
email: &str,
|
||||||
|
escrow: u64,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if escrow < MIN_ESCROW {
|
||||||
|
return Err(Error::MinimalEscrow);
|
||||||
|
}
|
||||||
|
let mut op_account = Self::get(db, wallet).await?;
|
||||||
|
let escrow = escrow.saturating_mul(TOKEN_DECIMAL);
|
||||||
|
let op_total_balance = op_account.balance.saturating_add(op_account.escrow);
|
||||||
|
if op_total_balance < escrow {
|
||||||
|
return Err(Error::InsufficientFunds);
|
||||||
|
}
|
||||||
|
op_account.email = email.to_string();
|
||||||
|
op_account.balance = op_total_balance.saturating_sub(escrow);
|
||||||
|
op_account.escrow = escrow;
|
||||||
|
op_account.save(db).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Account {
|
impl Account {
|
||||||
@ -84,7 +110,7 @@ impl From<&old_brain::BrainData> for Vec<Account> {
|
|||||||
let mut accounts = Vec::new();
|
let mut accounts = Vec::new();
|
||||||
for old_account in old_data.accounts.iter() {
|
for old_account in old_data.accounts.iter() {
|
||||||
let mut a = Account {
|
let mut a = Account {
|
||||||
id: RecordId::from(("account", old_account.key())),
|
id: RecordId::from((ACCOUNT, old_account.key())),
|
||||||
balance: old_account.value().balance,
|
balance: old_account.value().balance,
|
||||||
tmp_locked: old_account.value().tmp_locked,
|
tmp_locked: old_account.value().tmp_locked,
|
||||||
escrow: 0,
|
escrow: 0,
|
||||||
@ -120,6 +146,24 @@ pub struct Kick {
|
|||||||
created_at: Datetime,
|
created_at: Datetime,
|
||||||
reason: String,
|
reason: String,
|
||||||
contract: RecordId,
|
contract: RecordId,
|
||||||
|
node: RecordId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kick {
|
||||||
|
pub async fn kicked_in_a_day(db: &Surreal<Client>, account: &str) -> Result<Vec<Self>, Error> {
|
||||||
|
let mut result = db
|
||||||
|
.query(format!(
|
||||||
|
"select * from {KICK} where out = {ACCOUNT}:{account} and created_at > time::now() - 24h;"
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
let kicks: Vec<Self> = result.take(0)?;
|
||||||
|
Ok(kicks)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn submit(self, db: &Surreal<Client>) -> Result<(), Error> {
|
||||||
|
let _: Vec<Self> = db.insert(KICK).relation(self).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
@ -158,7 +202,7 @@ impl Report {
|
|||||||
|
|
||||||
/// This is the operator obtained from the DB,
|
/// This is the operator obtained from the DB,
|
||||||
/// however the relation is defined using OperatorRelation
|
/// however the relation is defined using OperatorRelation
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Operator {
|
pub struct Operator {
|
||||||
pub account: RecordId,
|
pub account: RecordId,
|
||||||
pub app_nodes: u64,
|
pub app_nodes: u64,
|
||||||
@ -231,3 +275,107 @@ impl Operator {
|
|||||||
Ok((operator, vm_nodes, app_nodes))
|
Ok((operator, vm_nodes, app_nodes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn kick_contract(
|
||||||
|
db: &Surreal<Client>,
|
||||||
|
operator_wallet: &str,
|
||||||
|
contract_uuid: &str,
|
||||||
|
reason: &str,
|
||||||
|
) -> Result<u64, Error> {
|
||||||
|
let (contract_id, operator_id, admin_id, app_or_vm) =
|
||||||
|
if let Some(active_vm) = ActiveVmWithNode::get_by_uuid(db, contract_uuid).await? {
|
||||||
|
(active_vm.id, active_vm.vm_node.operator, active_vm.admin, "vm")
|
||||||
|
} else if let Some(active_app) = ActiveAppWithNode::get_by_uuid(db, contract_uuid).await? {
|
||||||
|
(active_app.id, active_app.app_node.operator, active_app.admin, "app")
|
||||||
|
} else {
|
||||||
|
return Err(Error::ContractNotFound);
|
||||||
|
};
|
||||||
|
|
||||||
|
if operator_id.key().to_string() != operator_wallet {
|
||||||
|
return Err(Error::AccessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("Kicking contract {contract_id} by operator {operator_id} for reason: '{reason}'",);
|
||||||
|
|
||||||
|
let transaction_query = format!(
|
||||||
|
"
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
LET $contract = {contract_id};
|
||||||
|
LET $operator_account = {operator_id};
|
||||||
|
LET $reason = $reason_str_input;
|
||||||
|
LET $contract_id = record::id($contract.id);
|
||||||
|
LET $admin = $contract.in;
|
||||||
|
LET $node = $contract.out;
|
||||||
|
|
||||||
|
LET $active_contract = (select * from $contract)[0];
|
||||||
|
LET $deleted_contract = $active_contract.patch([{{
|
||||||
|
'op': 'replace',
|
||||||
|
'path': 'id',
|
||||||
|
'value': type::record('deleted_{app_or_vm}:' + $contract_id)
|
||||||
|
}}]);
|
||||||
|
LET $deleted_contract = (INSERT RELATION INTO deleted_{app_or_vm} ( $deleted_contract ) RETURN AFTER)[0];
|
||||||
|
|
||||||
|
-- calculating refund minutes
|
||||||
|
LET $one_week_minutes = duration::mins(1w);
|
||||||
|
LET $uncollected_minutes = (time::now() - $active_contract.collected_at).mins();
|
||||||
|
|
||||||
|
LET $minutes_to_refund = if $uncollected_minutes > $one_week_minutes {{
|
||||||
|
$one_week_minutes;
|
||||||
|
}} ELSE {{
|
||||||
|
$uncollected_minutes;
|
||||||
|
}};
|
||||||
|
|
||||||
|
-- calculating refund amount
|
||||||
|
LET $prince_per_minute = fn::{app_or_vm}_price_per_minute($active_contract.id);
|
||||||
|
|
||||||
|
LET $refund_amount = $prince_per_minute * $minutes_to_refund;
|
||||||
|
|
||||||
|
LET $refund = IF SELECT * FROM {KICK} WHERE out = $admin.id AND created_at > time::now() - 24h {{
|
||||||
|
0
|
||||||
|
}} ELSE IF $operator_account.escrow <= $refund_amount {{
|
||||||
|
$operator_account.escrow
|
||||||
|
}} ELSE {{
|
||||||
|
$refund_amount;
|
||||||
|
}};
|
||||||
|
|
||||||
|
RELATE $operator_account->{KICK}->$admin
|
||||||
|
SET id = $contract_id,
|
||||||
|
reason = $reason,
|
||||||
|
contract = $deleted_contract.id,
|
||||||
|
node = $node.id,
|
||||||
|
created_at = time::now()
|
||||||
|
;
|
||||||
|
DELETE $active_contract.id;
|
||||||
|
|
||||||
|
-- update balances
|
||||||
|
UPDATE $operator_account SET escrow -= $refund;
|
||||||
|
IF $operator_account.escrow < 0 {{
|
||||||
|
THROW 'Insufficient funds.'
|
||||||
|
}};
|
||||||
|
UPDATE $admin SET balance += $refund;
|
||||||
|
|
||||||
|
$refund;
|
||||||
|
|
||||||
|
COMMIT TRANSACTION;
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
log::trace!("kick_contract transaction_query: {}", &transaction_query);
|
||||||
|
|
||||||
|
let mut query_res =
|
||||||
|
db.query(transaction_query).bind(("reason_str_input", reason.to_string())).await?;
|
||||||
|
|
||||||
|
log::trace!("transaction_query response: {:?}", &query_res);
|
||||||
|
|
||||||
|
let query_error = query_res.take_errors();
|
||||||
|
if !query_error.is_empty() {
|
||||||
|
log::error!("kick_contract query error: {query_error:?}");
|
||||||
|
return Err(Error::FailedKickContract(contract_id.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let refunded: Option<u64> = query_res.take(20)?;
|
||||||
|
let refunded_amount = refunded.ok_or(Error::FailedToCreateDBEntry("Refund".to_string()))?;
|
||||||
|
log::info!("Refunded: {refunded_amount} to {admin_id}");
|
||||||
|
|
||||||
|
Ok(refunded_amount)
|
||||||
|
}
|
||||||
|
@ -2,7 +2,10 @@ pub mod app;
|
|||||||
pub mod general;
|
pub mod general;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|
||||||
use crate::constants::{APP_NODE, DELETED_APP, DELETED_VM, NEW_APP_REQ, NEW_VM_REQ, UPDATE_VM_REQ};
|
use crate::constants::{
|
||||||
|
APP_NODE, DB_SCHEMA_FILES, DELETED_APP, DELETED_VM, MIN_ESCROW, NEW_APP_REQ, NEW_VM_REQ,
|
||||||
|
UPDATE_VM_REQ,
|
||||||
|
};
|
||||||
use crate::old_brain;
|
use crate::old_brain;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -22,16 +25,26 @@ pub enum Error {
|
|||||||
StdIo(#[from] std::io::Error),
|
StdIo(#[from] std::io::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
TimeOut(#[from] tokio::time::error::Elapsed),
|
TimeOut(#[from] tokio::time::error::Elapsed),
|
||||||
#[error("Failed to create account")]
|
#[error("Failed to create {0}")]
|
||||||
FailedToCreateDBEntry,
|
FailedToCreateDBEntry(String),
|
||||||
#[error("Unknown Table: {0}")]
|
#[error("Unknown Table: {0}")]
|
||||||
UnknownTable(String),
|
UnknownTable(String),
|
||||||
#[error("Daemon channel got closed: {0}")]
|
#[error("Daemon channel got closed: {0}")]
|
||||||
AppDaemonConnection(#[from] tokio::sync::mpsc::error::SendError<AppDaemonMsg>),
|
AppDaemonConnection(#[from] tokio::sync::mpsc::error::SendError<AppDaemonMsg>),
|
||||||
#[error("AppDaemon Error {0}")]
|
#[error("AppDaemon Error {0}")]
|
||||||
NewAppDaemonResp(String),
|
NewAppDaemonResp(String),
|
||||||
|
#[error("Minimum escrow amount is {MIN_ESCROW}")]
|
||||||
|
MinimalEscrow,
|
||||||
#[error("Insufficient funds, deposit more tokens")]
|
#[error("Insufficient funds, deposit more tokens")]
|
||||||
InsufficientFunds,
|
InsufficientFunds,
|
||||||
|
#[error("Contract not found")]
|
||||||
|
ContractNotFound,
|
||||||
|
#[error("Access denied")]
|
||||||
|
AccessDenied,
|
||||||
|
#[error("Failed to delete contract {0}")]
|
||||||
|
FailedToDeleteContract(String),
|
||||||
|
#[error("Failed to kick contract {0}")]
|
||||||
|
FailedKickContract(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
@ -63,10 +76,15 @@ pub async fn migration0(
|
|||||||
let accounts: Vec<Account> = old_data.into();
|
let accounts: Vec<Account> = old_data.into();
|
||||||
let vm_nodes: Vec<VmNode> = old_data.into();
|
let vm_nodes: Vec<VmNode> = old_data.into();
|
||||||
let app_nodes: Vec<AppNode> = old_data.into();
|
let app_nodes: Vec<AppNode> = old_data.into();
|
||||||
let vm_contracts: Vec<ActiveVm> = old_data.into();
|
let active_vm: Vec<ActiveVm> = old_data.into();
|
||||||
|
let active_app: Vec<ActiveApp> = old_data.into();
|
||||||
|
|
||||||
let schema = std::fs::read_to_string(crate::constants::DB_SCHEMA_FILE)?;
|
for schema_data in DB_SCHEMA_FILES.map(|path| (std::fs::read_to_string(path), path)) {
|
||||||
db.query(schema).await?;
|
let schema_file = schema_data.1;
|
||||||
|
println!("Loading schema from {schema_file}");
|
||||||
|
let schema = schema_data.0?;
|
||||||
|
db.query(schema).await?;
|
||||||
|
}
|
||||||
|
|
||||||
println!("Inserting accounts...");
|
println!("Inserting accounts...");
|
||||||
let _: Vec<Account> = db.insert(()).content(accounts).await?;
|
let _: Vec<Account> = db.insert(()).content(accounts).await?;
|
||||||
@ -74,8 +92,10 @@ pub async fn migration0(
|
|||||||
let _: Vec<VmNode> = db.insert(()).content(vm_nodes).await?;
|
let _: Vec<VmNode> = db.insert(()).content(vm_nodes).await?;
|
||||||
println!("Inserting app nodes...");
|
println!("Inserting app nodes...");
|
||||||
let _: Vec<AppNode> = db.insert(()).content(app_nodes).await?;
|
let _: Vec<AppNode> = db.insert(()).content(app_nodes).await?;
|
||||||
println!("Inserting vm contracts...");
|
println!("Inserting active vm contracts...");
|
||||||
let _: Vec<ActiveVm> = db.insert("vm_contract").relation(vm_contracts).await?;
|
let _: Vec<ActiveVm> = db.insert(()).relation(active_vm).await?;
|
||||||
|
println!("Inserting app contracts...");
|
||||||
|
let _: Vec<ActiveApp> = db.insert(()).relation(active_app).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
46
src/db/vm.rs
46
src/db/vm.rs
@ -219,7 +219,7 @@ impl NewVmReq {
|
|||||||
->vm_node:{vm_node}
|
->vm_node:{vm_node}
|
||||||
CONTENT {{
|
CONTENT {{
|
||||||
created_at: time::now(), hostname: '{}', vcpus: {}, memory_mb: {}, disk_size_gb: {},
|
created_at: time::now(), hostname: '{}', vcpus: {}, memory_mb: {}, disk_size_gb: {},
|
||||||
extra_ports: {}, public_ipv4: {:?}, public_ipv6: {:?},
|
extra_ports: {:?}, public_ipv4: {:?}, public_ipv6: {:?},
|
||||||
dtrfs_url: '{}', dtrfs_sha: '{}', kernel_url: '{}', kernel_sha: '{}',
|
dtrfs_url: '{}', dtrfs_sha: '{}', kernel_url: '{}', kernel_sha: '{}',
|
||||||
price_per_unit: {}, locked_nano: {locked_nano}, error: ''
|
price_per_unit: {}, locked_nano: {locked_nano}, error: ''
|
||||||
}};
|
}};
|
||||||
@ -229,7 +229,7 @@ impl NewVmReq {
|
|||||||
self.vcpus,
|
self.vcpus,
|
||||||
self.memory_mb,
|
self.memory_mb,
|
||||||
self.disk_size_gb,
|
self.disk_size_gb,
|
||||||
format!("{:?}", self.extra_ports,),
|
self.extra_ports,
|
||||||
self.public_ipv4,
|
self.public_ipv4,
|
||||||
self.public_ipv6,
|
self.public_ipv6,
|
||||||
self.dtrfs_url,
|
self.dtrfs_url,
|
||||||
@ -242,13 +242,11 @@ impl NewVmReq {
|
|||||||
let mut query_resp = db.query(query).await?;
|
let mut query_resp = db.query(query).await?;
|
||||||
let resp_err = query_resp.take_errors();
|
let resp_err = query_resp.take_errors();
|
||||||
|
|
||||||
if let Some(insufficient_funds_error) = resp_err.get(&1) {
|
if let Some(surrealdb::Error::Api(surrealdb::error::Api::Query(tx_query_error))) =
|
||||||
if let surrealdb::Error::Api(surrealdb::error::Api::Query(tx_query_error)) =
|
resp_err.get(&1)
|
||||||
insufficient_funds_error
|
{
|
||||||
{
|
log::error!("Transaction error: {tx_query_error}");
|
||||||
log::error!("Transaction error: {}", tx_query_error);
|
return Err(Error::InsufficientFunds);
|
||||||
return Err(Error::InsufficientFunds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -728,10 +726,36 @@ pub struct ActiveVmWithNode {
|
|||||||
pub collected_at: Datetime,
|
pub collected_at: Datetime,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ActiveVmWithNode> for ActiveVm {
|
||||||
|
fn from(val: ActiveVmWithNode) -> Self {
|
||||||
|
Self {
|
||||||
|
id: val.id,
|
||||||
|
admin: val.admin,
|
||||||
|
vm_node: val.vm_node.id,
|
||||||
|
hostname: val.hostname,
|
||||||
|
mapped_ports: val.mapped_ports,
|
||||||
|
public_ipv4: val.public_ipv4,
|
||||||
|
public_ipv6: val.public_ipv6,
|
||||||
|
disk_size_gb: val.disk_size_gb,
|
||||||
|
vcpus: val.vcpus,
|
||||||
|
memory_mb: val.memory_mb,
|
||||||
|
dtrfs_sha: val.dtrfs_sha,
|
||||||
|
kernel_sha: val.kernel_sha,
|
||||||
|
created_at: val.created_at,
|
||||||
|
price_per_unit: val.price_per_unit,
|
||||||
|
locked_nano: val.locked_nano,
|
||||||
|
collected_at: val.collected_at,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveVmWithNode {
|
impl ActiveVmWithNode {
|
||||||
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
|
pub async fn get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
|
||||||
let contract: Option<Self> =
|
let contract: Option<Self> = db
|
||||||
db.query(format!("select * from {ACTIVE_VM}:{uuid} fetch out;")).await?.take(0)?;
|
.query(format!("select * from {ACTIVE_VM} where id = $uuid_input fetch out;"))
|
||||||
|
.bind(("uuid_input", RecordId::from((ACTIVE_VM, uuid))))
|
||||||
|
.await?
|
||||||
|
.take(0)?;
|
||||||
Ok(contract)
|
Ok(contract)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ impl BrainAppDaemon for AppDaemonServer {
|
|||||||
let mut req_stream = req.into_inner();
|
let mut req_stream = req.into_inner();
|
||||||
let pubkey: String;
|
let pubkey: String;
|
||||||
if let Some(Ok(msg)) = req_stream.next().await {
|
if let Some(Ok(msg)) = req_stream.next().await {
|
||||||
log::debug!("App daemon_messages received auth message: {:?}", msg);
|
log::debug!("App daemon_messages received auth message: {msg:?}");
|
||||||
if let Some(daemon_message_app::Msg::Auth(auth)) = msg.msg {
|
if let Some(daemon_message_app::Msg::Auth(auth)) = msg.msg {
|
||||||
pubkey = auth.pubkey.clone();
|
pubkey = auth.pubkey.clone();
|
||||||
check_sig_from_parts(
|
check_sig_from_parts(
|
||||||
|
@ -107,24 +107,49 @@ impl BrainGeneralCli for GeneralCliServer {
|
|||||||
|
|
||||||
async fn register_operator(
|
async fn register_operator(
|
||||||
&self,
|
&self,
|
||||||
_req: Request<RegOperatorReq>,
|
req: Request<RegOperatorReq>,
|
||||||
) -> Result<Response<Empty>, Status> {
|
) -> Result<Response<Empty>, Status> {
|
||||||
todo!();
|
let req = check_sig_from_req(req)?;
|
||||||
// let req = check_sig_from_req(req)?;
|
log::info!("Regitering new operator: {req:?}");
|
||||||
// info!("Regitering new operator: {req:?}");
|
match db::Account::operator_reg(&self.db, &req.pubkey, &req.email, req.escrow).await {
|
||||||
// match self.data.register_operator(req) {
|
Ok(()) => Ok(Response::new(Empty {})),
|
||||||
// Ok(()) => Ok(Response::new(Empty {})),
|
Err(e) if matches!(e, db::Error::InsufficientFunds | db::Error::MinimalEscrow) => {
|
||||||
// Err(e) => Err(Status::failed_precondition(e.to_string())),
|
Err(Status::failed_precondition(e.to_string()))
|
||||||
// }
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::info!("Failed to register operator: {e:?}");
|
||||||
|
Err(Status::unknown(
|
||||||
|
"Unknown error. Please try again or contact the DeTEE devs team.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn kick_contract(&self, _req: Request<KickReq>) -> Result<Response<KickResp>, Status> {
|
async fn kick_contract(&self, req: Request<KickReq>) -> Result<Response<KickResp>, Status> {
|
||||||
todo!();
|
let req = check_sig_from_req(req)?;
|
||||||
// let req = check_sig_from_req(req)?;
|
log::info!("Kicking contract: {}, by: {}", req.contract_uuid, req.operator_wallet);
|
||||||
// match self.data.kick_contract(&req.operator_wallet, &req.contract_uuid, &req.reason).await {
|
match db::kick_contract(&self.db, &req.operator_wallet, &req.contract_uuid, &req.reason)
|
||||||
// Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })),
|
.await
|
||||||
// Err(e) => Err(Status::permission_denied(e.to_string())),
|
{
|
||||||
// }
|
Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })),
|
||||||
|
Err(e)
|
||||||
|
if matches!(
|
||||||
|
e,
|
||||||
|
db::Error::ContractNotFound
|
||||||
|
| db::Error::AccessDenied
|
||||||
|
| db::Error::FailedToDeleteContract(_)
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
log::warn!("Failed to kick contract: {e:?}");
|
||||||
|
Err(Status::failed_precondition(e.to_string()))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to kick contract: {e:?}");
|
||||||
|
Err(Status::unknown(
|
||||||
|
"Unknown error. Please try again or contact the DeTEE devs team.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ban_user(&self, _req: Request<BanUserReq>) -> Result<Response<Empty>, Status> {
|
async fn ban_user(&self, _req: Request<BanUserReq>) -> Result<Response<Empty>, Status> {
|
||||||
|
@ -58,7 +58,7 @@ impl_pubkey_getter!(RegisterAppNodeReq);
|
|||||||
impl_pubkey_getter!(AppNodeFilters);
|
impl_pubkey_getter!(AppNodeFilters);
|
||||||
|
|
||||||
pub fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
pub fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
||||||
log::trace!("Checking signature from request: {:?}", req);
|
log::trace!("Checking signature from request: {req:?}");
|
||||||
let time = match req.metadata().get("timestamp") {
|
let time = match req.metadata().get("timestamp") {
|
||||||
Some(t) => t.clone(),
|
Some(t) => t.clone(),
|
||||||
None => return Err(Status::unauthenticated("Timestamp not found in metadata.")),
|
None => return Err(Status::unauthenticated("Timestamp not found in metadata.")),
|
||||||
@ -73,8 +73,7 @@ pub fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) ->
|
|||||||
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
||||||
if !(-4..=4).contains(&seconds_elapsed) {
|
if !(-4..=4).contains(&seconds_elapsed) {
|
||||||
return Err(Status::unauthenticated(format!(
|
return Err(Status::unauthenticated(format!(
|
||||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
"Date is not within 4 sec of the time of the server: CLI {parsed_time} vs Server {now}",
|
||||||
parsed_time, now
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +130,7 @@ pub fn check_sig_from_parts(pubkey: &str, time: &str, msg: &str, sig: &str) -> R
|
|||||||
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
||||||
if !(-4..=4).contains(&seconds_elapsed) {
|
if !(-4..=4).contains(&seconds_elapsed) {
|
||||||
return Err(Status::unauthenticated(format!(
|
return Err(Status::unauthenticated(format!(
|
||||||
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
"Date is not within 4 sec of the time of the server: CLI {parsed_time} vs Server {now}",
|
||||||
parsed_time, now
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,15 +263,15 @@ impl From<db::ActiveAppWithNode> for AppContract {
|
|||||||
node_pubkey: value.app_node.id.key().to_string(),
|
node_pubkey: value.app_node.id.key().to_string(),
|
||||||
public_ipv4: value.host_ipv4,
|
public_ipv4: value.host_ipv4,
|
||||||
resource: Some(AppResource {
|
resource: Some(AppResource {
|
||||||
memory_mb: value.memory_mb as u32,
|
memory_mb: value.memory_mb,
|
||||||
disk_mb: value.disk_size_gb as u32,
|
disk_mb: value.disk_size_gb,
|
||||||
vcpu: value.vcpus as u32,
|
vcpu: value.vcpus,
|
||||||
ports: value.mapped_ports.iter().map(|(_, g)| *g as u32).collect(),
|
ports: value.mapped_ports.iter().map(|(_, g)| *g).collect(),
|
||||||
}),
|
}),
|
||||||
mapped_ports: value
|
mapped_ports: value
|
||||||
.mapped_ports
|
.mapped_ports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(h, g)| MappedPort { host_port: *h as u32, guest_port: *g as u32 })
|
.map(|(h, g)| MappedPort { host_port: *h, guest_port: *g })
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
created_at: value.created_at.to_rfc3339(),
|
created_at: value.created_at.to_rfc3339(),
|
||||||
@ -294,7 +294,7 @@ impl From<NewAppReq> for db::NewAppReq {
|
|||||||
.public_package_mr_enclave
|
.public_package_mr_enclave
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.iter()
|
.iter()
|
||||||
.fold(String::new(), |acc, x| acc + &format!("{:02x?}", x));
|
.fold(String::new(), |acc, x| acc + &format!("{x:02x?}"));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id: RecordId::from((NEW_APP_REQ, nanoid!(40, &ID_ALPHABET))),
|
id: RecordId::from((NEW_APP_REQ, nanoid!(40, &ID_ALPHABET))),
|
||||||
@ -377,7 +377,7 @@ impl From<db::ActiveApp> for NewAppRes {
|
|||||||
let mapped_ports = val
|
let mapped_ports = val
|
||||||
.mapped_ports
|
.mapped_ports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(h, g)| MappedPort { host_port: *h as u32, guest_port: *g as u32 })
|
.map(|(h, g)| MappedPort { host_port: *h, guest_port: *g })
|
||||||
.collect();
|
.collect();
|
||||||
Self {
|
Self {
|
||||||
uuid: val.id.key().to_string(),
|
uuid: val.id.key().to_string(),
|
||||||
|
@ -25,3 +25,13 @@ DEFINE FUNCTION OVERWRITE fn::delete_vm(
|
|||||||
DELETE $vm.id;
|
DELETE $vm.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEFINE FUNCTION OVERWRITE fn::app_price_per_minute(
|
||||||
|
$app_id: record
|
||||||
|
) {
|
||||||
|
LET $app = (select * from $app_id)[0];
|
||||||
|
RETURN
|
||||||
|
(($app.vcpus * 5) +
|
||||||
|
($app.memory_mb / 200) +
|
||||||
|
($app.disk_size_gb / 10))
|
||||||
|
* $app.price_per_unit;
|
||||||
|
};
|
@ -129,10 +129,8 @@ DEFINE FIELD vcpus ON TABLE deleted_app TYPE int;
|
|||||||
DEFINE FIELD memory_mb ON TABLE deleted_app TYPE int;
|
DEFINE FIELD memory_mb ON TABLE deleted_app TYPE int;
|
||||||
DEFINE FIELD disk_size_gb ON TABLE deleted_app TYPE int;
|
DEFINE FIELD disk_size_gb ON TABLE deleted_app TYPE int;
|
||||||
DEFINE FIELD created_at ON TABLE deleted_app TYPE datetime;
|
DEFINE FIELD created_at ON TABLE deleted_app TYPE datetime;
|
||||||
DEFINE FIELD deleted_at ON TABLE deleted_app TYPE datetime;
|
DEFINE FIELD deleted_at ON TABLE deleted_app TYPE datetime DEFAULT time::now();;
|
||||||
DEFINE FIELD price_per_unit ON TABLE deleted_app TYPE int;
|
DEFINE FIELD price_per_unit ON TABLE deleted_app TYPE int;
|
||||||
DEFINE FIELD locked_nano ON TABLE deleted_app TYPE int;
|
|
||||||
DEFINE FIELD collected_at ON TABLE deleted_app TYPE datetime;
|
|
||||||
DEFINE FIELD mr_enclave ON TABLE deleted_app TYPE string;
|
DEFINE FIELD mr_enclave ON TABLE deleted_app TYPE string;
|
||||||
DEFINE FIELD package_url ON TABLE deleted_app TYPE string;
|
DEFINE FIELD package_url ON TABLE deleted_app TYPE string;
|
||||||
DEFINE FIELD hratls_pubkey ON TABLE deleted_app TYPE string;
|
DEFINE FIELD hratls_pubkey ON TABLE deleted_app TYPE string;
|
||||||
@ -144,6 +142,7 @@ DEFINE TABLE kick TYPE RELATION FROM account TO account;
|
|||||||
DEFINE FIELD created_at ON TABLE kick TYPE datetime;
|
DEFINE FIELD created_at ON TABLE kick TYPE datetime;
|
||||||
DEFINE FIELD reason ON TABLE kick TYPE string;
|
DEFINE FIELD reason ON TABLE kick TYPE string;
|
||||||
DEFINE FIELD contract ON TABLE kick TYPE record<deleted_vm|deleted_app>;
|
DEFINE FIELD contract ON TABLE kick TYPE record<deleted_vm|deleted_app>;
|
||||||
|
DEFINE FIELD node ON TABLE kick TYPE record<vm_node|app_node>;
|
||||||
|
|
||||||
DEFINE TABLE report TYPE RELATION FROM account TO vm_node|app_node;
|
DEFINE TABLE report TYPE RELATION FROM account TO vm_node|app_node;
|
||||||
DEFINE FIELD created_at ON TABLE report TYPE datetime;
|
DEFINE FIELD created_at ON TABLE report TYPE datetime;
|
||||||
|
@ -6,6 +6,7 @@ use dotenv::dotenv;
|
|||||||
use hyper_util::rt::TokioIo;
|
use hyper_util::rt::TokioIo;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use surreal_brain::constants::DB_SCHEMA_FILES;
|
||||||
use surreal_brain::grpc::general::GeneralCliServer;
|
use surreal_brain::grpc::general::GeneralCliServer;
|
||||||
use surreal_brain::grpc::vm::{VmCliServer, VmDaemonServer};
|
use surreal_brain::grpc::vm::{VmCliServer, VmDaemonServer};
|
||||||
use surrealdb::engine::remote::ws::Client;
|
use surrealdb::engine::remote::ws::Client;
|
||||||
@ -34,7 +35,9 @@ pub async fn prepare_test_db() -> Result<Surreal<Client>> {
|
|||||||
.map_err(|e| anyhow!(e.to_string()))?;
|
.map_err(|e| anyhow!(e.to_string()))?;
|
||||||
|
|
||||||
db.query(format!("REMOVE DATABASE {db_name}")).await?;
|
db.query(format!("REMOVE DATABASE {db_name}")).await?;
|
||||||
db.query(std::fs::read_to_string("interim_tables.surql")?).await?;
|
for schema in DB_SCHEMA_FILES.map(std::fs::read_to_string) {
|
||||||
|
db.query(schema?).await?;
|
||||||
|
}
|
||||||
surreal_brain::db::migration0(&db, &old_brain_data).await?;
|
surreal_brain::db::migration0(&db, &old_brain_data).await?;
|
||||||
Ok::<(), anyhow::Error>(())
|
Ok::<(), anyhow::Error>(())
|
||||||
})
|
})
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use detee_shared::vm_proto as snp_proto;
|
use detee_shared::vm_proto as snp_proto;
|
||||||
use ed25519_dalek::{Signer, SigningKey};
|
use ed25519_dalek::{Signer, SigningKey};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::sync::OnceLock;
|
||||||
use tonic::metadata::AsciiMetadataValue;
|
use tonic::metadata::AsciiMetadataValue;
|
||||||
use tonic::Request;
|
use tonic::Request;
|
||||||
|
|
||||||
|
pub static ADMIN_KEYS: OnceLock<Vec<Key>> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn admin_keys() -> Vec<Key> {
|
||||||
|
let admin_keys = ADMIN_KEYS.get_or_init(|| {
|
||||||
|
let admin_keys = vec![Key::new(), Key::new(), Key::new()];
|
||||||
|
let admin_pub_keys = admin_keys.iter().map(|k| k.pubkey.clone()).join(", ");
|
||||||
|
std::env::set_var("ADMIN_PUB_KEYS", admin_pub_keys);
|
||||||
|
admin_keys.clone()
|
||||||
|
});
|
||||||
|
|
||||||
|
admin_keys.clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Key {
|
pub struct Key {
|
||||||
pub sg_key: SigningKey,
|
pub sg_key: SigningKey,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::test_utils::Key;
|
use super::test_utils::{admin_keys, Key};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use detee_shared::common_proto::Empty;
|
use detee_shared::common_proto::Empty;
|
||||||
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
|
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
|
||||||
@ -11,12 +11,11 @@ use surrealdb::engine::remote::ws::Client;
|
|||||||
use surrealdb::Surreal;
|
use surrealdb::Surreal;
|
||||||
use tonic::transport::Channel;
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
async fn airdrop(brain_channel: &Channel, wallet: &str, amount: u64) -> Result<()> {
|
pub async fn airdrop(brain_channel: &Channel, wallet: &str, amount: u64) -> Result<()> {
|
||||||
let mut client = BrainGeneralCliClient::new(brain_channel.clone());
|
let mut client = BrainGeneralCliClient::new(brain_channel.clone());
|
||||||
let airdrop_req = AirdropReq { pubkey: wallet.to_string(), tokens: amount };
|
let airdrop_req = AirdropReq { pubkey: wallet.to_string(), tokens: amount };
|
||||||
|
|
||||||
let admin_key = Key::new();
|
let admin_key = admin_keys()[0].clone();
|
||||||
std::env::set_var("ADMIN_PUB_KEYS", &admin_key.pubkey);
|
|
||||||
|
|
||||||
client.airdrop(admin_key.sign_request(airdrop_req.clone())?).await?;
|
client.airdrop(admin_key.sign_request(airdrop_req.clone())?).await?;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ pub async fn register_vm_node(
|
|||||||
client: &mut BrainVmDaemonClient<Channel>,
|
client: &mut BrainVmDaemonClient<Channel>,
|
||||||
key: &Key,
|
key: &Key,
|
||||||
operator_wallet: &str,
|
operator_wallet: &str,
|
||||||
) -> Result<Vec<vm_proto::VmContract>> {
|
) -> Result<Vec<vm_proto::DeleteVmReq>> {
|
||||||
log::info!("Registering vm_node: {}", key.pubkey);
|
log::info!("Registering vm_node: {}", key.pubkey);
|
||||||
let node_pubkey = key.pubkey.clone();
|
let node_pubkey = key.pubkey.clone();
|
||||||
|
|
||||||
@ -53,18 +53,18 @@ pub async fn register_vm_node(
|
|||||||
|
|
||||||
let mut grpc_stream = client.register_vm_node(key.sign_request(req)?).await?.into_inner();
|
let mut grpc_stream = client.register_vm_node(key.sign_request(req)?).await?.into_inner();
|
||||||
|
|
||||||
let mut vm_contracts = Vec::new();
|
let mut deleted_vm_reqs = Vec::new();
|
||||||
while let Some(stream_update) = grpc_stream.next().await {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
Ok(vm_c) => {
|
Ok(del_vm_rq) => {
|
||||||
vm_contracts.push(vm_c);
|
deleted_vm_reqs.push(del_vm_rq);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Received error instead of vm_contracts: {e:?}");
|
panic!("Received error instead of deleted_vm_reqs: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(vm_contracts)
|
Ok(deleted_vm_reqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn daemon_listener(
|
pub async fn daemon_listener(
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
use common::prepare_test_env::{
|
use common::prepare_test_env::{
|
||||||
prepare_test_db, run_service_for_stream, run_service_in_background,
|
prepare_test_db, run_service_for_stream, run_service_in_background,
|
||||||
};
|
};
|
||||||
use common::test_utils::Key;
|
use common::test_utils::{admin_keys, Key};
|
||||||
use common::vm_cli_utils::{create_new_vm, report_node};
|
use common::vm_cli_utils::{airdrop, create_new_vm, report_node};
|
||||||
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
||||||
use detee_shared::common_proto::{Empty, Pubkey};
|
use detee_shared::common_proto::{Empty, Pubkey};
|
||||||
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
|
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
|
||||||
use detee_shared::general_proto::AirdropReq;
|
use detee_shared::general_proto::AirdropReq;
|
||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
|
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use itertools::Itertools;
|
use surreal_brain::constants::{TOKEN_DECIMAL, VM_NODE};
|
||||||
use std::vec;
|
|
||||||
use surreal_brain::constants::VM_NODE;
|
|
||||||
use surreal_brain::db::vm::VmNodeWithReports;
|
use surreal_brain::db::vm::VmNodeWithReports;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
@ -41,15 +39,12 @@ async fn test_general_airdrop() {
|
|||||||
// env_logger::builder().filter_level(log::LevelFilter::Trace).init();
|
// env_logger::builder().filter_level(log::LevelFilter::Trace).init();
|
||||||
prepare_test_db().await.unwrap();
|
prepare_test_db().await.unwrap();
|
||||||
|
|
||||||
const AIRDROP_MULTIPLE: u64 = 1_000_000_000;
|
|
||||||
let airdrop_amount = 10;
|
let airdrop_amount = 10;
|
||||||
|
|
||||||
let addr = run_service_in_background().await.unwrap();
|
let addr = run_service_in_background().await.unwrap();
|
||||||
let mut client = BrainGeneralCliClient::connect(format!("http://{}", addr)).await.unwrap();
|
let mut client = BrainGeneralCliClient::connect(format!("http://{}", addr)).await.unwrap();
|
||||||
|
|
||||||
let admin_keys = vec![Key::new(), Key::new(), Key::new()];
|
let admin_keys = admin_keys();
|
||||||
let admin_pub_keys = admin_keys.iter().map(|k| k.pubkey.clone()).join(", ");
|
|
||||||
std::env::set_var("ADMIN_PUB_KEYS", admin_pub_keys);
|
|
||||||
|
|
||||||
let user_01_key = Key::new();
|
let user_01_key = Key::new();
|
||||||
let user_01_pubkey = user_01_key.pubkey.clone();
|
let user_01_pubkey = user_01_key.pubkey.clone();
|
||||||
@ -72,7 +67,7 @@ async fn test_general_airdrop() {
|
|||||||
let bal_req = user_01_key.sign_request(bal_req_data.clone()).unwrap();
|
let bal_req = user_01_key.sign_request(bal_req_data.clone()).unwrap();
|
||||||
let acc_bal_user_01 = client.get_balance(bal_req).await.unwrap().into_inner();
|
let acc_bal_user_01 = client.get_balance(bal_req).await.unwrap().into_inner();
|
||||||
|
|
||||||
assert_eq!(acc_bal_user_01.balance, airdrop_amount * AIRDROP_MULTIPLE);
|
assert_eq!(acc_bal_user_01.balance, airdrop_amount * TOKEN_DECIMAL);
|
||||||
assert_eq!(acc_bal_user_01.tmp_locked, 0);
|
assert_eq!(acc_bal_user_01.tmp_locked, 0);
|
||||||
|
|
||||||
// second airdrop from same admin
|
// second airdrop from same admin
|
||||||
@ -84,7 +79,7 @@ async fn test_general_airdrop() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
assert_eq!(acc_bal_user_01.balance, 2 * airdrop_amount * AIRDROP_MULTIPLE);
|
assert_eq!(acc_bal_user_01.balance, 2 * airdrop_amount * TOKEN_DECIMAL);
|
||||||
|
|
||||||
// third airdrop from another admin
|
// third airdrop from another admin
|
||||||
let _ = client.airdrop(admin_keys[1].sign_request(airdrop_req.clone()).unwrap()).await.unwrap();
|
let _ = client.airdrop(admin_keys[1].sign_request(airdrop_req.clone()).unwrap()).await.unwrap();
|
||||||
@ -95,7 +90,7 @@ async fn test_general_airdrop() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
assert_eq!(acc_bal_user_01.balance, 3 * airdrop_amount * AIRDROP_MULTIPLE);
|
assert_eq!(acc_bal_user_01.balance, 3 * airdrop_amount * TOKEN_DECIMAL);
|
||||||
|
|
||||||
// self airdrop
|
// self airdrop
|
||||||
let airdrop_req = AirdropReq { pubkey: admin_keys[2].pubkey.clone(), tokens: airdrop_amount };
|
let airdrop_req = AirdropReq { pubkey: admin_keys[2].pubkey.clone(), tokens: airdrop_amount };
|
||||||
@ -109,7 +104,7 @@ async fn test_general_airdrop() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
assert_eq!(acc_bal_admin_3.balance, airdrop_amount * AIRDROP_MULTIPLE);
|
assert_eq!(acc_bal_admin_3.balance, airdrop_amount * TOKEN_DECIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -127,6 +122,8 @@ async fn test_report_node() {
|
|||||||
log::info!("Report error: {:?}", report_error);
|
log::info!("Report error: {:?}", report_error);
|
||||||
assert!(report_error.to_string().contains("No contract found by this ID."));
|
assert!(report_error.to_string().contains("No contract found by this ID."));
|
||||||
|
|
||||||
|
airdrop(&brain_channel, &key.pubkey, 10).await.unwrap();
|
||||||
|
|
||||||
let active_vm_id = create_new_vm(&db, &key, &daemon_key, &brain_channel).await.unwrap();
|
let active_vm_id = create_new_vm(&db, &key, &daemon_key, &brain_channel).await.unwrap();
|
||||||
|
|
||||||
let reason = String::from("something went wrong on vm");
|
let reason = String::from("something went wrong on vm");
|
||||||
@ -211,3 +208,39 @@ async fn test_inspect_operator() {
|
|||||||
assert!(!inspect_response.vm_nodes.is_empty());
|
assert!(!inspect_response.vm_nodes.is_empty());
|
||||||
assert_eq!(&inspect_response.vm_nodes[0].operator, &operator_key.pubkey);
|
assert_eq!(&inspect_response.vm_nodes[0].operator, &operator_key.pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_kick_contract() {
|
||||||
|
// TODO: implement seed data to test
|
||||||
|
// possibilities
|
||||||
|
// 1. vm contract
|
||||||
|
// 2. app contract
|
||||||
|
// 3. non existent contract
|
||||||
|
// 4. other operator's contract
|
||||||
|
// 5. contract collected more than a week
|
||||||
|
// 6. refund amount calculation
|
||||||
|
// 7. refund of multiple contract kick in a day for same user
|
||||||
|
|
||||||
|
env_logger::builder()
|
||||||
|
.filter_level(log::LevelFilter::Info)
|
||||||
|
.filter_module("tungstenite", log::LevelFilter::Debug)
|
||||||
|
.filter_module("tokio_tungstenite", log::LevelFilter::Debug)
|
||||||
|
.init();
|
||||||
|
|
||||||
|
let db_conn = prepare_test_db().await.unwrap();
|
||||||
|
let contract_uuid = "e3d01f252b2a410b80e312f44e474334";
|
||||||
|
let operator_wallet = "7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB";
|
||||||
|
let reason = "'; THROW 'Injected error'; --"; // sql injection query
|
||||||
|
|
||||||
|
let kick_response =
|
||||||
|
surreal_brain::db::general::kick_contract(&db_conn, operator_wallet, contract_uuid, reason)
|
||||||
|
.await;
|
||||||
|
match kick_response {
|
||||||
|
Ok(refund_amount) => {
|
||||||
|
println!("Refund amount: {}", refund_amount);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
|
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
|
||||||
use common::test_utils::Key;
|
use common::test_utils::Key;
|
||||||
use common::vm_cli_utils::create_new_vm;
|
use common::vm_cli_utils::{airdrop, create_new_vm};
|
||||||
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
||||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
|
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
|
||||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
|
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
|
||||||
use detee_shared::vm_proto::{ListVmContractsReq, NewVmReq};
|
use detee_shared::vm_proto::{ListVmContractsReq, NewVmReq};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
use surreal_brain::constants::ACTIVE_VM;
|
||||||
|
use surreal_brain::db::vm::ActiveVm;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
@ -26,7 +28,11 @@ async fn test_vm_creation() {
|
|||||||
let grpc_error_message = new_vm_resp.err().unwrap().to_string();
|
let grpc_error_message = new_vm_resp.err().unwrap().to_string();
|
||||||
assert!(grpc_error_message.contains("Insufficient funds"));
|
assert!(grpc_error_message.contains("Insufficient funds"));
|
||||||
|
|
||||||
// TODO: Airdrop the user and try creating the VM again
|
airdrop(&brain_channel, &key.pubkey, 10).await.unwrap();
|
||||||
|
|
||||||
|
let new_vm_id = create_new_vm(&db, &key, &daemon_key, &brain_channel).await.unwrap();
|
||||||
|
let active_vm: Option<ActiveVm> = db.select((ACTIVE_VM, new_vm_id)).await.unwrap();
|
||||||
|
assert!(active_vm.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -51,6 +57,8 @@ async fn test_timeout_vm_creation() {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
airdrop(&brain_channel, &key.pubkey, 10).await.unwrap();
|
||||||
|
|
||||||
let mut client_vm_cli = BrainVmCliClient::new(brain_channel.clone());
|
let mut client_vm_cli = BrainVmCliClient::new(brain_channel.clone());
|
||||||
let timeout_error =
|
let timeout_error =
|
||||||
client_vm_cli.new_vm(key.sign_request(new_vm_req).unwrap()).await.err().unwrap();
|
client_vm_cli.new_vm(key.sign_request(new_vm_req).unwrap()).await.err().unwrap();
|
||||||
|
@ -2,6 +2,7 @@ use common::prepare_test_env::{
|
|||||||
prepare_test_db, run_service_for_stream, run_service_in_background,
|
prepare_test_db, run_service_for_stream, run_service_in_background,
|
||||||
};
|
};
|
||||||
use common::test_utils::Key;
|
use common::test_utils::Key;
|
||||||
|
use common::vm_cli_utils::airdrop;
|
||||||
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
use common::vm_daemon_utils::{mock_vm_daemon, register_vm_node};
|
||||||
use detee_shared::vm_proto;
|
use detee_shared::vm_proto;
|
||||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
|
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
|
||||||
@ -29,7 +30,7 @@ async fn test_brain_message() {
|
|||||||
|
|
||||||
let brain_channel = run_service_for_stream().await.unwrap();
|
let brain_channel = run_service_for_stream().await.unwrap();
|
||||||
let daemon_key = mock_vm_daemon(&brain_channel).await.unwrap();
|
let daemon_key = mock_vm_daemon(&brain_channel).await.unwrap();
|
||||||
let mut cli_client = BrainVmCliClient::new(brain_channel);
|
let mut cli_client = BrainVmCliClient::new(brain_channel.clone());
|
||||||
|
|
||||||
let cli_key = Key::new();
|
let cli_key = Key::new();
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ async fn test_brain_message() {
|
|||||||
locked_nano: 0,
|
locked_nano: 0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
airdrop(&brain_channel, &cli_key.pubkey, 10).await.unwrap();
|
||||||
let new_vm_resp =
|
let new_vm_resp =
|
||||||
cli_client.new_vm(cli_key.sign_request(req).unwrap()).await.unwrap().into_inner();
|
cli_client.new_vm(cli_key.sign_request(req).unwrap()).await.unwrap().into_inner();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user