Compare commits
	
		
			No commits in common. "871e26edc2293b4ffe46f83e672453169fb4b660" and "ee1b12f85f8ab71c4e14afeda47a71ed14b4c6d4" have entirely different histories.
		
	
	
		
			871e26edc2
			...
			ee1b12f85f
		
	
		
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1011,7 +1011,7 @@ dependencies = [
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "detee-shared"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=credits_app#01e93d3a2e4502c0e8e72026e8a1c55810961815"
 | 
			
		||||
source = "git+ssh://git@gitea.detee.cloud/testnet/proto?branch=surreal_brain_app#0b195b4589e4ec689af7ddca27dc051716ecee78"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bincode 2.0.1",
 | 
			
		||||
 "prost",
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ serde_yaml = "0.9.34"
 | 
			
		||||
surrealdb = "2.2.2"
 | 
			
		||||
tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] }
 | 
			
		||||
tonic = { version = "0.12", features = ["tls"] }
 | 
			
		||||
detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto", branch = "credits_app" }
 | 
			
		||||
detee-shared = { git = "ssh://git@gitea.detee.cloud/testnet/proto", branch = "surreal_brain_app" }
 | 
			
		||||
ed25519-dalek = "2.1.1"
 | 
			
		||||
bs58 = "0.5.1"
 | 
			
		||||
tokio-stream = "0.1.17"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										686
									
								
								saved_data.yaml
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										686
									
								
								saved_data.yaml
									
									
									
									
									
								
							@ -1,12 +1,80 @@
 | 
			
		||||
# SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 | 
			
		||||
accounts:
 | 
			
		||||
  fY3NNjvFTeR1FBh5nXV3ujX7zZqrm3eBUWGEiG75TK1:
 | 
			
		||||
    balance: 1000000000
 | 
			
		||||
  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
			
		||||
    balance: 20293420000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  FBMWVqME3t1i4R6zWyDQGUuiTeruZ1TxLhTmhaEcFypZ:
 | 
			
		||||
    balance: 181560160000
 | 
			
		||||
  FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL:
 | 
			
		||||
    balance: 25949200000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  Cnkvn3WuHYfTzh1YK1TAv2VD25sNvstJNnQtxjcdQSL7:
 | 
			
		||||
    balance: 4794480000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS:
 | 
			
		||||
    balance: 4672207240000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  E3bgXsWvgichXeC6AqULJCZDp7FbEdTxBD67UaYVWf9y:
 | 
			
		||||
    balance: 21121600000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  HQyGWpiteHbxjszngZvmiX7ZFZAmF6nFjEraBa1M6bbM:
 | 
			
		||||
    balance: 979410300000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc:
 | 
			
		||||
    balance: 976000000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  45Pyv9hRfub43NyRrYv95MhZs1Wrm8sj3RhBvA3F1Bvr:
 | 
			
		||||
    balance: 1670441080000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  49JBVzmgsQbUURHzAWax2gxo6jmukqbEQzP97YeeNQyu:
 | 
			
		||||
    balance: 1076960680000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB:
 | 
			
		||||
    balance: 3271040000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
 | 
			
		||||
    balance: 554454460000
 | 
			
		||||
    tmp_locked: 547200000
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  3BNggj8ZTsoSjfAGdPfmcU2Gobm2qcTEBg9iHXEUPe1t:
 | 
			
		||||
    balance: 9978460000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  B981xPHmHthfKr15J9uJ64qd9zt2KsdiEuDRR7UUCGWi:
 | 
			
		||||
    balance: 99980200000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
@ -23,316 +91,352 @@ accounts:
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  49JBVzmgsQbUURHzAWax2gxo6jmukqbEQzP97YeeNQyu:
 | 
			
		||||
    balance: 1076960680000
 | 
			
		||||
  fY3NNjvFTeR1FBh5nXV3ujX7zZqrm3eBUWGEiG75TK1:
 | 
			
		||||
    balance: 1000000000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  HQyGWpiteHbxjszngZvmiX7ZFZAmF6nFjEraBa1M6bbM:
 | 
			
		||||
    balance: 979410300000
 | 
			
		||||
  FBMWVqME3t1i4R6zWyDQGUuiTeruZ1TxLhTmhaEcFypZ:
 | 
			
		||||
    balance: 181560160000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  E3bgXsWvgichXeC6AqULJCZDp7FbEdTxBD67UaYVWf9y:
 | 
			
		||||
    balance: 21121600000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL:
 | 
			
		||||
    balance: 1156240000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  45Pyv9hRfub43NyRrYv95MhZs1Wrm8sj3RhBvA3F1Bvr:
 | 
			
		||||
    balance: 933585660000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc:
 | 
			
		||||
    balance: 109066280000
 | 
			
		||||
    tmp_locked: 453600000
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
 | 
			
		||||
    balance: 2565079420000
 | 
			
		||||
    tmp_locked: 547200000
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB:
 | 
			
		||||
    balance: 7063640000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS:
 | 
			
		||||
    balance: 13535509680000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  E27C967A84DEAA3339B4D57C1A7321E4906772244BBECCE25356D0EA6F851086:
 | 
			
		||||
    balance: 100000000000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  DwfL5iFu32xh2YMCUxg63OeaThLRqehDAumiP9q6zuuX:
 | 
			
		||||
  DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX:
 | 
			
		||||
    balance: 74660380000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  DXXkYSnhP3ijsHYxkedcuMomEyc122WaAbkDX7SaGuUS:
 | 
			
		||||
    balance: 20293420000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  Bb5Xfkk4fc5i4GiTEgChwMb1ToWDQ5uzGtgD6yKTQYAy:
 | 
			
		||||
    balance: 99979600000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  5hx2f3odEx6sXqCY6FEAv6bBm3BXdhJ97G6X7uScsLAj:
 | 
			
		||||
    balance: 94473640000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  3BNggj8ZTsoSjfAGdPfmcU2Gobm2qcTEBg9iHXEUPe1t:
 | 
			
		||||
    balance: 9978460000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  B981xPHmHthfKr15J9uJ64qd9zt2KsdiEuDRR7UUCGWi:
 | 
			
		||||
    balance: 99980200000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
  Cnkvn3WuHYfTzh1YK1TAv2VD25sNvstJNnQtxjcdQSL7:
 | 
			
		||||
    balance: 11021340000
 | 
			
		||||
    tmp_locked: 0
 | 
			
		||||
    kicked_for: []
 | 
			
		||||
    last_kick: 1970-01-01T00:00:00Z
 | 
			
		||||
    banned_by: []
 | 
			
		||||
operators:
 | 
			
		||||
  x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
 | 
			
		||||
    escrow: 5489633280000
 | 
			
		||||
    email: gheo@detee.ltd
 | 
			
		||||
    banned_users: []
 | 
			
		||||
    vm_nodes:
 | 
			
		||||
    - 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
 | 
			
		||||
    - 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
 | 
			
		||||
    app_nodes: []
 | 
			
		||||
  BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS:
 | 
			
		||||
    escrow: 5091906400000
 | 
			
		||||
    escrow: 5096692000000
 | 
			
		||||
    email: first_on_detee@proton.me
 | 
			
		||||
    banned_users: []
 | 
			
		||||
    vm_nodes:
 | 
			
		||||
    - DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
    - 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
    - Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
      - HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
 | 
			
		||||
      - 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
      - Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
      - 4QbUXDM915RUFnHm3NiysLXFLk1WRGZvABwLNzx4tTEW
 | 
			
		||||
      - DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
    app_nodes: []
 | 
			
		||||
  x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK:
 | 
			
		||||
    escrow: 5499700480000
 | 
			
		||||
    email: gheo@detee.ltd
 | 
			
		||||
    banned_users: []
 | 
			
		||||
    vm_nodes:
 | 
			
		||||
      - 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
 | 
			
		||||
      - 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
 | 
			
		||||
    app_nodes: []
 | 
			
		||||
  7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB:
 | 
			
		||||
    escrow: 5500000000000
 | 
			
		||||
    email: nmohammed@detee.ltd
 | 
			
		||||
    escrow: 888888888899999
 | 
			
		||||
    email: ""
 | 
			
		||||
    banned_users: []
 | 
			
		||||
    vm_nodes: []
 | 
			
		||||
    app_nodes:
 | 
			
		||||
    - BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
 | 
			
		||||
      - BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
 | 
			
		||||
vm_nodes:
 | 
			
		||||
- public_key: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
  operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
  country: FR
 | 
			
		||||
  region: Île-de-France
 | 
			
		||||
  city: Paris
 | 
			
		||||
  ip: 156.146.63.215
 | 
			
		||||
  avail_mem_mb: 117000
 | 
			
		||||
  avail_vcpus: 40
 | 
			
		||||
  avail_storage_gbs: 410
 | 
			
		||||
  avail_ipv4: 2
 | 
			
		||||
  avail_ipv6: 0
 | 
			
		||||
  avail_ports: 20000
 | 
			
		||||
  max_ports_per_vm: 5
 | 
			
		||||
  price: 20000
 | 
			
		||||
  reports: {}
 | 
			
		||||
  offline_minutes: 0
 | 
			
		||||
- public_key: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
  operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
  country: US
 | 
			
		||||
  region: California
 | 
			
		||||
  city: San Jose
 | 
			
		||||
  ip: 149.36.48.99
 | 
			
		||||
  avail_mem_mb: 121000
 | 
			
		||||
  avail_vcpus: 42
 | 
			
		||||
  avail_storage_gbs: 400
 | 
			
		||||
  avail_ipv4: 23
 | 
			
		||||
  avail_ipv6: 0
 | 
			
		||||
  avail_ports: 20000
 | 
			
		||||
  max_ports_per_vm: 5
 | 
			
		||||
  price: 20000
 | 
			
		||||
  reports: {}
 | 
			
		||||
  offline_minutes: 0
 | 
			
		||||
- public_key: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
  operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
  country: CA
 | 
			
		||||
  region: British Columbia
 | 
			
		||||
  city: Vancouver
 | 
			
		||||
  ip: 149.22.95.1
 | 
			
		||||
  avail_mem_mb: 106400
 | 
			
		||||
  avail_vcpus: 42
 | 
			
		||||
  avail_storage_gbs: 400
 | 
			
		||||
  avail_ipv4: 25
 | 
			
		||||
  avail_ipv6: 0
 | 
			
		||||
  avail_ports: 19999
 | 
			
		||||
  max_ports_per_vm: 5
 | 
			
		||||
  price: 20000
 | 
			
		||||
  reports: {}
 | 
			
		||||
  offline_minutes: 0
 | 
			
		||||
- public_key: 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
 | 
			
		||||
  operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
 | 
			
		||||
  country: CA
 | 
			
		||||
  region: Quebec
 | 
			
		||||
  city: Montréal
 | 
			
		||||
  ip: 184.107.169.199
 | 
			
		||||
  avail_mem_mb: 29000
 | 
			
		||||
  avail_vcpus: 30
 | 
			
		||||
  avail_storage_gbs: 700
 | 
			
		||||
  avail_ipv4: 0
 | 
			
		||||
  avail_ipv6: 0
 | 
			
		||||
  avail_ports: 19999
 | 
			
		||||
  max_ports_per_vm: 5
 | 
			
		||||
  price: 18000
 | 
			
		||||
  reports: {}
 | 
			
		||||
  offline_minutes: 0
 | 
			
		||||
  - public_key: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
 | 
			
		||||
    operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
 | 
			
		||||
    country: GB
 | 
			
		||||
    region: England
 | 
			
		||||
    city: London
 | 
			
		||||
    ip: 173.234.17.2
 | 
			
		||||
    avail_mem_mb: 26000
 | 
			
		||||
    avail_vcpus: 28
 | 
			
		||||
    avail_storage_gbs: 680
 | 
			
		||||
    avail_ipv4: 2
 | 
			
		||||
    avail_ipv6: 65516
 | 
			
		||||
    avail_ports: 19999
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 20000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
  - public_key: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
    operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
    country: FR
 | 
			
		||||
    region: Île-de-France
 | 
			
		||||
    city: Paris
 | 
			
		||||
    ip: 156.146.63.215
 | 
			
		||||
    avail_mem_mb: 123000
 | 
			
		||||
    avail_vcpus: 46
 | 
			
		||||
    avail_storage_gbs: 440
 | 
			
		||||
    avail_ipv4: 2
 | 
			
		||||
    avail_ipv6: 0
 | 
			
		||||
    avail_ports: 20000
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 20000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
  - public_key: 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
 | 
			
		||||
    operator_wallet: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
 | 
			
		||||
    country: CA
 | 
			
		||||
    region: Quebec
 | 
			
		||||
    city: Montréal
 | 
			
		||||
    ip: 184.107.169.199
 | 
			
		||||
    avail_mem_mb: 30000
 | 
			
		||||
    avail_vcpus: 31
 | 
			
		||||
    avail_storage_gbs: 700
 | 
			
		||||
    avail_ipv4: 0
 | 
			
		||||
    avail_ipv6: 0
 | 
			
		||||
    avail_ports: 20000
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 18000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
  - public_key: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
    operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
    country: CA
 | 
			
		||||
    region: British Columbia
 | 
			
		||||
    city: Vancouver
 | 
			
		||||
    ip: 149.22.95.1
 | 
			
		||||
    avail_mem_mb: 109000
 | 
			
		||||
    avail_vcpus: 45
 | 
			
		||||
    avail_storage_gbs: 400
 | 
			
		||||
    avail_ipv4: 25
 | 
			
		||||
    avail_ipv6: 0
 | 
			
		||||
    avail_ports: 20000
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 20000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
  - public_key: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
    operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
    country: US
 | 
			
		||||
    region: California
 | 
			
		||||
    city: San Jose
 | 
			
		||||
    ip: 149.36.48.99
 | 
			
		||||
    avail_mem_mb: 120000
 | 
			
		||||
    avail_vcpus: 41
 | 
			
		||||
    avail_storage_gbs: 390
 | 
			
		||||
    avail_ipv4: 23
 | 
			
		||||
    avail_ipv6: 0
 | 
			
		||||
    avail_ports: 19999
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 20000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
  - public_key: HiyMp21zaBVbRCjDsD5hEjQnHeHv4e1gpUR6pVfHTKqv
 | 
			
		||||
    operator_wallet: BFopWmwcZAMF1h2PFECZNdEucdZfnZZ32p6R9ZaBiVsS
 | 
			
		||||
    country: CA
 | 
			
		||||
    region: British Columbia
 | 
			
		||||
    city: Vancouver
 | 
			
		||||
    ip: 149.22.95.28
 | 
			
		||||
    avail_mem_mb: 125000
 | 
			
		||||
    avail_vcpus: 46
 | 
			
		||||
    avail_storage_gbs: 400
 | 
			
		||||
    avail_ipv4: 26
 | 
			
		||||
    avail_ipv6: 0
 | 
			
		||||
    avail_ports: 20000
 | 
			
		||||
    max_ports_per_vm: 5
 | 
			
		||||
    price: 20000
 | 
			
		||||
    reports: {}
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
vm_contracts:
 | 
			
		||||
- uuid: dbe09a11-0bcf-472e-9f27-9a4939ea2226
 | 
			
		||||
  hostname: detee-fr
 | 
			
		||||
  admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
  node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
  exposed_ports: []
 | 
			
		||||
  public_ipv4: 156.146.63.217
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 10
 | 
			
		||||
  vcpus: 4
 | 
			
		||||
  memory_mb: 4000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-05-16T11:07:53.903282009Z
 | 
			
		||||
  updated_at: 2025-05-16T11:07:53.903282959Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 24513120000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521517733Z
 | 
			
		||||
- uuid: 338312387c6e4e5ebec015277d27c21d
 | 
			
		||||
  hostname: sofenty-staging
 | 
			
		||||
  admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
  node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
  exposed_ports: []
 | 
			
		||||
  public_ipv4: 149.22.95.3
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 10
 | 
			
		||||
  vcpus: 2
 | 
			
		||||
  memory_mb: 4000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-06-12T23:20:23.797184848Z
 | 
			
		||||
  updated_at: 2025-06-12T23:20:23.797185855Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 17703920000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521538185Z
 | 
			
		||||
- uuid: 46656273dc964fdeaec2fd1efd49fc12
 | 
			
		||||
  hostname: sofenty-scraper-bot
 | 
			
		||||
  admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
  node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
  exposed_ports:
 | 
			
		||||
  - 36057
 | 
			
		||||
  public_ipv4: ''
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 10
 | 
			
		||||
  vcpus: 2
 | 
			
		||||
  memory_mb: 4000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-06-17T11:12:18.659422501Z
 | 
			
		||||
  updated_at: 2025-06-17T11:12:18.659423285Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 14299320000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521547200Z
 | 
			
		||||
- uuid: 1b3365a15fe64b8aa283bb7883c62e09
 | 
			
		||||
  hostname: detee-us
 | 
			
		||||
  admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
  node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
  exposed_ports: []
 | 
			
		||||
  public_ipv4: 149.36.48.100
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 10
 | 
			
		||||
  vcpus: 4
 | 
			
		||||
  memory_mb: 4000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-06-18T10:51:17.699206021Z
 | 
			
		||||
  updated_at: 2025-06-18T10:51:17.699206835Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 26552160000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521554160Z
 | 
			
		||||
- uuid: b11ad0fcfc194f5490d64f5a72574dc8
 | 
			
		||||
  hostname: brain-backups
 | 
			
		||||
  admin_pubkey: 45Pyv9hRfub43NyRrYv95MhZs1Wrm8sj3RhBvA3F1Bvr
 | 
			
		||||
  node_pubkey: 2Uf5pxhxKTUm6gRMnpbJHYDuyA6BWUfFsdmPyWfbMV1f
 | 
			
		||||
  exposed_ports:
 | 
			
		||||
  - 38175
 | 
			
		||||
  public_ipv4: ''
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 30
 | 
			
		||||
  vcpus: 1
 | 
			
		||||
  memory_mb: 1000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-06-18T13:59:30.713579315Z
 | 
			
		||||
  updated_at: 2025-06-18T13:59:30.713580515Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 11638260000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521562057Z
 | 
			
		||||
- uuid: 89237736b97047beac3611e25e26408e
 | 
			
		||||
  hostname: brain-staging
 | 
			
		||||
  admin_pubkey: 45Pyv9hRfub43NyRrYv95MhZs1Wrm8sj3RhBvA3F1Bvr
 | 
			
		||||
  node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
  exposed_ports: []
 | 
			
		||||
  public_ipv4: 156.146.63.216
 | 
			
		||||
  public_ipv6: ''
 | 
			
		||||
  disk_size_gb: 20
 | 
			
		||||
  vcpus: 2
 | 
			
		||||
  memory_mb: 4000
 | 
			
		||||
  kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
  dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
  created_at: 2025-06-18T14:00:48.016735075Z
 | 
			
		||||
  updated_at: 2025-06-18T14:00:48.016736647Z
 | 
			
		||||
  price_per_unit: 20000
 | 
			
		||||
  locked_nano: 32466740000
 | 
			
		||||
  collected_at: 2025-06-26T11:32:59.521568755Z
 | 
			
		||||
  - uuid: 958165e3-dea8-407d-8c42-dd17002ef79c
 | 
			
		||||
    hostname: detee-landing-fr
 | 
			
		||||
    admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
    node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 156.146.63.216
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
 | 
			
		||||
    dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
 | 
			
		||||
    created_at: 2025-02-28T23:19:41.769423466Z
 | 
			
		||||
    updated_at: 2025-04-12T12:11:58.516768949Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 14875500000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461165181Z
 | 
			
		||||
  - uuid: e807a2fd-cf90-4a14-bc3a-89ce6dc59033
 | 
			
		||||
    hostname: detee-landing-gb
 | 
			
		||||
    admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
    node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 173.234.136.154
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
 | 
			
		||||
    dtrfs_sha: 3f6b3e5740f249eedfb2f7248c521a551be8b2676f7fcb040f3f3bc840a5004b
 | 
			
		||||
    created_at: 2025-03-06T19:51:39.595163157Z
 | 
			
		||||
    updated_at: 2025-03-06T19:51:39.595163842Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 14875500000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461181545Z
 | 
			
		||||
  - uuid: 23094406-2307-4332-a642-acee718d0186
 | 
			
		||||
    hostname: heroic-door
 | 
			
		||||
    admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
 | 
			
		||||
    node_pubkey: 7Xw3RxbP5pvfjZ8U6yA3HHVSS9YXjKH5Vkas3JRbQYd9
 | 
			
		||||
    exposed_ports:
 | 
			
		||||
      - 38288
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: 14e225e4aaf84cc2e0b5f64206121186ddebc4b378b886da3b2f7515dfd41692
 | 
			
		||||
    dtrfs_sha: 03ce24dbbe917fdd4f6347e61036805ddbdded5044c272bab188ef9333093bee
 | 
			
		||||
    created_at: 2025-03-12T16:28:24.749161605Z
 | 
			
		||||
    updated_at: 2025-03-12T16:28:24.749162477Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 14134140000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461191231Z
 | 
			
		||||
  - uuid: 1f49a71c-f68c-4c64-a82e-f50e0ba0b574
 | 
			
		||||
    hostname: astromech-wrench
 | 
			
		||||
    admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
    node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 149.22.95.2
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3a68709138bed09c16671949cf1f03acee95a08381ba84fc70fb586001fa6767
 | 
			
		||||
    dtrfs_sha: 0bb93443f65c9f4379ed469f94794f5c1bf14d8905b0b2c56a125df4a9ebe83e
 | 
			
		||||
    created_at: 2025-03-20T14:40:25.557753393Z
 | 
			
		||||
    updated_at: 2025-03-20T14:40:25.557754242Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 11865620000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461201690Z
 | 
			
		||||
  - uuid: 16577f1c-9867-4a17-80a8-6cf0490f1270
 | 
			
		||||
    hostname: sofenty
 | 
			
		||||
    admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
    node_pubkey: Du3UfPSUUZmA5thQmc9Vrxdy7UimpygcpDsQNnwRQPtu
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 156.146.63.217
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
 | 
			
		||||
    dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
 | 
			
		||||
    created_at: 2025-04-07T22:57:57.646151746Z
 | 
			
		||||
    updated_at: 2025-04-07T22:57:57.646152630Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 11867500000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461211040Z
 | 
			
		||||
  - uuid: 4b6e25ca-87ac-478b-8f16-aa8f5c44c704
 | 
			
		||||
    hostname: cloaked-mailbox
 | 
			
		||||
    admin_pubkey: DwfL5iFu32xh2YMCUxg63oEAThLRqehDAumiP9q6zuuX
 | 
			
		||||
    node_pubkey: DgkbsrwttkZXvzxY5kDwQQoDd79GLmZ5tc7fYJUFkQQb
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 149.22.95.2
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 30
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
 | 
			
		||||
    dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
 | 
			
		||||
    created_at: 2025-04-12T13:44:56.957037550Z
 | 
			
		||||
    updated_at: 2025-04-12T13:44:56.957038546Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 11177760000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461219779Z
 | 
			
		||||
  - uuid: eb1a13ed-d782-4b71-8860-73540129cb7d
 | 
			
		||||
    hostname: twenty
 | 
			
		||||
    admin_pubkey: FHuecMbeC1PfjkW2JKyoicJAuiU7khgQT16QUB3Q1XdL
 | 
			
		||||
    node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 149.36.48.100
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 4
 | 
			
		||||
    memory_mb: 4000
 | 
			
		||||
    kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
 | 
			
		||||
    dtrfs_sha: b5f408d00e2b93dc594fed3a7f2466a9878802ff1c7ae502247471cd06728a45
 | 
			
		||||
    created_at: 2025-04-15T00:46:35.622165457Z
 | 
			
		||||
    updated_at: 2025-04-15T00:46:35.622166372Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 15570720000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461230948Z
 | 
			
		||||
  - uuid: 1bf36309-3774-4825-b023-b2a0ef0405ed
 | 
			
		||||
    hostname: shadowy-hobo
 | 
			
		||||
    admin_pubkey: x52w7jARC5erhWWK65VZmjdGXzBK6ZDgfv1A283d8XK
 | 
			
		||||
    node_pubkey: 3zRxiGRnf46vd3zAEmpaYBJocTV9oJB6yXf5GZFR1Sq4
 | 
			
		||||
    exposed_ports:
 | 
			
		||||
      - 46393
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
    dtrfs_sha: d207644ee60d54009b6ecdfb720e2ec251cde31774dd249fcc7435aca0377990
 | 
			
		||||
    created_at: 2025-04-16T20:37:57.176592933Z
 | 
			
		||||
    updated_at: 2025-04-16T20:37:57.176594069Z
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 12730960000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461240342Z
 | 
			
		||||
app_nodes:
 | 
			
		||||
- node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
 | 
			
		||||
  operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB
 | 
			
		||||
  country: DE
 | 
			
		||||
  region: Hesse
 | 
			
		||||
  city: Frankfurt am Main
 | 
			
		||||
  ip: 212.95.45.139
 | 
			
		||||
  avail_mem_mb: 16000
 | 
			
		||||
  avail_vcpus: 16
 | 
			
		||||
  avail_storage_mb: 200000
 | 
			
		||||
  avail_no_of_port: 20000
 | 
			
		||||
  max_ports_per_app: 9
 | 
			
		||||
  price: 20000
 | 
			
		||||
  reports: {}
 | 
			
		||||
  offline_minutes: 0
 | 
			
		||||
app_contracts: []
 | 
			
		||||
  - node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
 | 
			
		||||
    operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB
 | 
			
		||||
    country: DE
 | 
			
		||||
    region: Hesse
 | 
			
		||||
    city: Frankfurt am Main
 | 
			
		||||
    ip: 212.95.45.139
 | 
			
		||||
    avail_mem_mb: 16000
 | 
			
		||||
    avail_vcpus: 16
 | 
			
		||||
    avail_storage_mb: 200000
 | 
			
		||||
    avail_no_of_port: 20000
 | 
			
		||||
    max_ports_per_app: 9
 | 
			
		||||
    price: 20000
 | 
			
		||||
    offline_minutes: 0
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ server="$1"
 | 
			
		||||
  exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[ "$server" == "testnet" ]] && server="brain-testnet"
 | 
			
		||||
[[ "$server" == "testnet" ]] && server="root@prod-brain-1"
 | 
			
		||||
[[ "$server" == "staging" ]] && server="brain-staging"
 | 
			
		||||
 | 
			
		||||
cargo build --release --bin brain
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@ pub const ID_ALPHABET: [char; 62] = [
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub const TOKEN_DECIMAL: u64 = 1_000_000_000;
 | 
			
		||||
pub const MIN_ESCROW: u64 = 5000 * TOKEN_DECIMAL;
 | 
			
		||||
 | 
			
		||||
pub const APP_DAEMON_TIMEOUT: u64 = 20;
 | 
			
		||||
pub const VM_DAEMON_TIMEOUT: u64 = 10;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										108
									
								
								src/db/app.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										108
									
								
								src/db/app.rs
									
									
									
									
									
								
							@ -6,8 +6,9 @@ use super::Error;
 | 
			
		||||
use crate::constants::{
 | 
			
		||||
    ACCOUNT, ACTIVE_APP, APP_DAEMON_TIMEOUT, APP_NODE, DEFAULT_ENDPOINT, DELETED_APP, NEW_APP_REQ,
 | 
			
		||||
};
 | 
			
		||||
use crate::db;
 | 
			
		||||
use crate::db::general::Report;
 | 
			
		||||
use crate::{db, old_brain};
 | 
			
		||||
use crate::old_brain;
 | 
			
		||||
use detee_shared::app_proto::{self, NewAppRes};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use surrealdb::engine::remote::ws::Client;
 | 
			
		||||
@ -24,14 +25,13 @@ pub struct AppNode {
 | 
			
		||||
    pub region: String,
 | 
			
		||||
    pub city: String,
 | 
			
		||||
    pub ip: String,
 | 
			
		||||
    pub avail_mem_mib: u32,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_storage_mib: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
    pub max_ports_per_app: u32,
 | 
			
		||||
    pub price: u64,
 | 
			
		||||
    pub connected_at: Datetime,
 | 
			
		||||
    pub disconnected_at: Datetime,
 | 
			
		||||
    pub offline_minutes: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppNode {
 | 
			
		||||
@ -41,18 +41,6 @@ impl AppNode {
 | 
			
		||||
        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}")))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn set_online(db: &Surreal<Client>, app_node_id: &str) -> Result<(), Error> {
 | 
			
		||||
        db.query(format!("UPDATE {APP_NODE}:{app_node_id} SET connected_at = time::now();"))
 | 
			
		||||
            .await?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn set_offline(db: &Surreal<Client>, app_node_id: &str) -> Result<(), Error> {
 | 
			
		||||
        db.query(format!("UPDATE {APP_NODE}:{app_node_id} SET disconnected_at = time::now();"))
 | 
			
		||||
            .await?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum AppDaemonMsg {
 | 
			
		||||
@ -84,9 +72,9 @@ pub struct NewAppReq {
 | 
			
		||||
    pub mr_enclave: String,
 | 
			
		||||
    pub hratls_pubkey: String,
 | 
			
		||||
    pub ports: Vec<u32>,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub locked_nano: u64,
 | 
			
		||||
    pub price_per_unit: u64,
 | 
			
		||||
    pub error: String,
 | 
			
		||||
@ -177,12 +165,12 @@ impl NewAppReq {
 | 
			
		||||
                    ->$app_node
 | 
			
		||||
                CONTENT {{
 | 
			
		||||
                    created_at: time::now(), app_name: $app_name, package_url: $package_url,
 | 
			
		||||
                    mr_enclave: $mr_enclave, hratls_pubkey: $hratls_pubkey, ports: {:?}, memory_mib: {},
 | 
			
		||||
                    vcpus: {}, disk_size_mib: {}, locked_nano: {locked_nano}, price_per_unit: {}, error: '',
 | 
			
		||||
                    mr_enclave: $mr_enclave, hratls_pubkey: $hratls_pubkey, ports: {:?}, memory_mb: {},
 | 
			
		||||
                    vcpus: {}, disk_size_gb: {}, locked_nano: {locked_nano}, price_per_unit: {}, error: '',
 | 
			
		||||
                }};
 | 
			
		||||
 | 
			
		||||
            COMMIT TRANSACTION;",
 | 
			
		||||
            self.ports, self.memory_mib, self.vcpus, self.disk_size_mib, self.price_per_unit);
 | 
			
		||||
            self.ports, self.memory_mb, self.vcpus, self.disk_size_gb, self.price_per_unit);
 | 
			
		||||
 | 
			
		||||
        log::trace!("submit_new_app_req query: {tx_query}");
 | 
			
		||||
 | 
			
		||||
@ -224,12 +212,13 @@ pub struct AppNodeWithReports {
 | 
			
		||||
    pub region: String,
 | 
			
		||||
    pub city: String,
 | 
			
		||||
    pub ip: String,
 | 
			
		||||
    pub avail_mem_mib: u32,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_storage_mib: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
    pub max_ports_per_app: u32,
 | 
			
		||||
    pub price: u64,
 | 
			
		||||
    pub offline_minutes: u64,
 | 
			
		||||
    pub reports: Vec<Report>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -244,13 +233,13 @@ impl AppNodeWithReports {
 | 
			
		||||
            avail_ports >= {} &&
 | 
			
		||||
            max_ports_per_app >= {} &&
 | 
			
		||||
            avail_vcpus >= {} &&
 | 
			
		||||
            avail_mem_mib >= {} &&
 | 
			
		||||
            avail_storage_mib >= {} ",
 | 
			
		||||
            avail_mem_mb >= {} &&
 | 
			
		||||
            avail_storage_gbs >= {} ",
 | 
			
		||||
            filters.free_ports,
 | 
			
		||||
            filters.free_ports,
 | 
			
		||||
            filters.vcpus,
 | 
			
		||||
            filters.memory_mib,
 | 
			
		||||
            filters.storage_mib
 | 
			
		||||
            filters.memory_mb,
 | 
			
		||||
            filters.storage_gb
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // TODO: bind all strings
 | 
			
		||||
@ -267,8 +256,6 @@ impl AppNodeWithReports {
 | 
			
		||||
            filter_query += &format!("&& ip = '{}' ", filters.ip);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        filter_query += " && connected_at > disconnected_at ";
 | 
			
		||||
 | 
			
		||||
        if limit_one {
 | 
			
		||||
            filter_query += "limit 1";
 | 
			
		||||
        }
 | 
			
		||||
@ -291,8 +278,8 @@ pub struct ActiveApp {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub host_ipv4: String,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
    pub price_per_unit: u64,
 | 
			
		||||
    pub locked_nano: u64,
 | 
			
		||||
@ -312,8 +299,8 @@ impl From<ActiveApp> for DeletedApp {
 | 
			
		||||
            mapped_ports: value.mapped_ports,
 | 
			
		||||
            host_ipv4: value.host_ipv4,
 | 
			
		||||
            vcpus: value.vcpus,
 | 
			
		||||
            memory_mib: value.memory_mib,
 | 
			
		||||
            disk_size_mib: value.disk_size_mib,
 | 
			
		||||
            memory_mb: value.memory_mb,
 | 
			
		||||
            disk_size_gb: value.disk_size_gb,
 | 
			
		||||
            created_at: value.created_at,
 | 
			
		||||
            price_per_unit: value.price_per_unit,
 | 
			
		||||
            mr_enclave: value.mr_enclave,
 | 
			
		||||
@ -324,6 +311,15 @@ impl From<ActiveApp> for DeletedApp {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 get_by_uuid(db: &Surreal<Client>, uuid: &str) -> Result<Option<Self>, Error> {
 | 
			
		||||
        let contract: Option<Self> = db
 | 
			
		||||
            .query("select * from $active_app_id;".to_string())
 | 
			
		||||
@ -356,8 +352,8 @@ impl ActiveApp {
 | 
			
		||||
            mapped_ports,
 | 
			
		||||
            host_ipv4: new_app_res.ip_address,
 | 
			
		||||
            vcpus: new_app_req.vcpus,
 | 
			
		||||
            memory_mib: new_app_req.memory_mib,
 | 
			
		||||
            disk_size_mib: new_app_req.disk_size_mib,
 | 
			
		||||
            memory_mb: new_app_req.memory_mb,
 | 
			
		||||
            disk_size_gb: new_app_req.disk_size_gb,
 | 
			
		||||
            created_at: new_app_req.created_at.clone(),
 | 
			
		||||
            price_per_unit: new_app_req.price_per_unit,
 | 
			
		||||
            locked_nano: new_app_req.locked_nano,
 | 
			
		||||
@ -371,7 +367,7 @@ impl ActiveApp {
 | 
			
		||||
        let locked_nano = active_app.locked_nano;
 | 
			
		||||
 | 
			
		||||
        let _: Vec<ActiveApp> = db.insert(()).relation(active_app).await?;
 | 
			
		||||
        NewAppReq::delete(db, &new_app_res.uuid).await?;
 | 
			
		||||
        NewAppReq::delete(&db, &new_app_res.uuid).await?;
 | 
			
		||||
        db.query(format!("UPDATE {ACCOUNT}:{admin_account} SET tmp_locked -= {locked_nano};"))
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
@ -502,8 +498,8 @@ pub struct ActiveAppWithNode {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub host_ipv4: String,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
    pub price_per_unit: u64,
 | 
			
		||||
    pub locked_nano: u64,
 | 
			
		||||
@ -523,8 +519,8 @@ impl From<ActiveAppWithNode> for ActiveApp {
 | 
			
		||||
            mapped_ports: val.mapped_ports,
 | 
			
		||||
            host_ipv4: val.host_ipv4,
 | 
			
		||||
            vcpus: val.vcpus,
 | 
			
		||||
            memory_mib: val.memory_mib,
 | 
			
		||||
            disk_size_mib: val.disk_size_mib,
 | 
			
		||||
            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,
 | 
			
		||||
@ -592,17 +588,6 @@ impl ActiveAppWithNode {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn total_units(&self) -> f64 {
 | 
			
		||||
        // TODO: Optimize this based on price of hardware.
 | 
			
		||||
        (self.vcpus as f64 * 5f64)
 | 
			
		||||
            + (self.memory_mib as f64 / 200f64)
 | 
			
		||||
            + (self.disk_size_mib as f64 / 1024f64 / 10f64)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn price_per_minute(&self) -> u64 {
 | 
			
		||||
        (self.total_units() * self.price_per_unit as f64) as u64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn list_all(db: &Surreal<Client>) -> Result<Vec<Self>, Error> {
 | 
			
		||||
        let mut query_response = db.query(format!("SELECT * FROM {ACTIVE_APP} FETCH out;")).await?;
 | 
			
		||||
        let active_apps: Vec<Self> = query_response.take(0)?;
 | 
			
		||||
@ -614,8 +599,8 @@ impl ActiveAppWithNode {
 | 
			
		||||
pub struct AppNodeResources {
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_mem_mib: u32,
 | 
			
		||||
    pub avail_storage_mib: u32,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub max_ports_per_app: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -643,14 +628,13 @@ impl From<&old_brain::BrainData> for Vec<AppNode> {
 | 
			
		||||
                region: old_node.region.clone(),
 | 
			
		||||
                city: old_node.city.clone(),
 | 
			
		||||
                ip: old_node.ip.clone(),
 | 
			
		||||
                avail_mem_mib: old_node.avail_mem_mb,
 | 
			
		||||
                avail_mem_mb: old_node.avail_mem_mb,
 | 
			
		||||
                avail_vcpus: old_node.avail_vcpus,
 | 
			
		||||
                avail_storage_mib: old_node.avail_storage_mb,
 | 
			
		||||
                avail_storage_gbs: old_node.avail_storage_mb,
 | 
			
		||||
                avail_ports: old_node.avail_no_of_port,
 | 
			
		||||
                max_ports_per_app: old_node.max_ports_per_app,
 | 
			
		||||
                price: old_node.price,
 | 
			
		||||
                disconnected_at: Datetime::default(),
 | 
			
		||||
                connected_at: Datetime::default(),
 | 
			
		||||
                offline_minutes: old_node.offline_minutes,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        nodes
 | 
			
		||||
@ -680,9 +664,9 @@ impl From<&old_brain::BrainData> for Vec<ActiveApp> {
 | 
			
		||||
                app_node: RecordId::from((APP_NODE, old_c.node_pubkey.clone())),
 | 
			
		||||
                mapped_ports,
 | 
			
		||||
                host_ipv4: old_c.host_ipv4.clone(),
 | 
			
		||||
                disk_size_mib: old_c.disk_size_mb,
 | 
			
		||||
                disk_size_gb: old_c.disk_size_mb * 1024,
 | 
			
		||||
                vcpus: old_c.vcpus,
 | 
			
		||||
                memory_mib: old_c.memory_mb,
 | 
			
		||||
                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(),
 | 
			
		||||
@ -708,8 +692,8 @@ pub struct DeletedApp {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub host_ipv4: String,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
    pub price_per_unit: u64,
 | 
			
		||||
    pub mr_enclave: String,
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 | 
			
		||||
use super::Error;
 | 
			
		||||
use crate::constants::{ACCOUNT, BAN, KICK, TOKEN_DECIMAL, VM_NODE};
 | 
			
		||||
use crate::constants::{ACCOUNT, BAN, KICK, MIN_ESCROW, VM_NODE};
 | 
			
		||||
use crate::db::prelude::*;
 | 
			
		||||
use crate::old_brain;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
@ -61,7 +61,9 @@ impl Account {
 | 
			
		||||
        email: &str,
 | 
			
		||||
        escrow: u64,
 | 
			
		||||
    ) -> Result<(), Error> {
 | 
			
		||||
        let escrow = escrow.saturating_mul(TOKEN_DECIMAL);
 | 
			
		||||
        if escrow < MIN_ESCROW {
 | 
			
		||||
            return Err(Error::MinimalEscrow);
 | 
			
		||||
        }
 | 
			
		||||
        let mut op_account = Self::get(db, wallet).await?;
 | 
			
		||||
        let op_total_balance = op_account.balance.saturating_add(op_account.escrow);
 | 
			
		||||
        if op_total_balance < escrow {
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,8 @@ pub mod general;
 | 
			
		||||
pub mod vm;
 | 
			
		||||
 | 
			
		||||
use crate::constants::{
 | 
			
		||||
    APP_NODE, DB_SCHEMA_FILES, DEFAULT_ENDPOINT, DELETED_APP, DELETED_VM, NEW_APP_REQ, NEW_VM_REQ,
 | 
			
		||||
    UPDATE_VM_REQ,
 | 
			
		||||
    APP_NODE, DB_SCHEMA_FILES, DEFAULT_ENDPOINT, DELETED_APP, DELETED_VM, MIN_ESCROW, NEW_APP_REQ,
 | 
			
		||||
    NEW_VM_REQ, UPDATE_VM_REQ,
 | 
			
		||||
};
 | 
			
		||||
use crate::old_brain;
 | 
			
		||||
use prelude::*;
 | 
			
		||||
@ -33,6 +33,8 @@ pub enum Error {
 | 
			
		||||
    UnknownTable(String),
 | 
			
		||||
    #[error("Daemon channel got closed: {0}")]
 | 
			
		||||
    AppDaemonConnection(#[from] tokio::sync::mpsc::error::SendError<AppDaemonMsg>),
 | 
			
		||||
    #[error("Minimum escrow amount is {MIN_ESCROW}")]
 | 
			
		||||
    MinimalEscrow,
 | 
			
		||||
    #[error("Insufficient funds, deposit more tokens")]
 | 
			
		||||
    InsufficientFunds,
 | 
			
		||||
    #[error("Contract not found")]
 | 
			
		||||
@ -99,7 +101,7 @@ pub async fn migration0(
 | 
			
		||||
    println!("Inserting vm nodes...");
 | 
			
		||||
    let _: Vec<VmNode> = db.insert(()).content(vm_nodes).await?;
 | 
			
		||||
    println!("Inserting app nodes...");
 | 
			
		||||
    let _: Vec<AppNode> = db.insert(()).content(app_nodes).await.unwrap();
 | 
			
		||||
    let _: Vec<AppNode> = db.insert(()).content(app_nodes).await?;
 | 
			
		||||
    println!("Inserting active vm contracts...");
 | 
			
		||||
    let _: Vec<ActiveVm> = db.insert(()).relation(active_vm).await?;
 | 
			
		||||
    println!("Inserting app contracts...");
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										120
									
								
								src/db/vm.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										120
									
								
								src/db/vm.rs
									
									
									
									
									
								
							@ -26,9 +26,9 @@ pub struct VmNode {
 | 
			
		||||
    pub region: String,
 | 
			
		||||
    pub city: String,
 | 
			
		||||
    pub ip: String,
 | 
			
		||||
    pub avail_mem_mib: u32,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_storage_mib: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub avail_ipv4: u32,
 | 
			
		||||
    pub avail_ipv6: u32,
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
@ -59,9 +59,9 @@ impl VmNode {
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct VmNodeResources {
 | 
			
		||||
    pub avail_mem_mib: u32,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_storage_mib: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub avail_ipv4: u32,
 | 
			
		||||
    pub avail_ipv6: u32,
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
@ -83,9 +83,9 @@ pub struct VmNodeWithReports {
 | 
			
		||||
    pub region: String,
 | 
			
		||||
    pub city: String,
 | 
			
		||||
    pub ip: String,
 | 
			
		||||
    pub avail_mem_mib: u64,
 | 
			
		||||
    pub avail_vcpus: u64,
 | 
			
		||||
    pub avail_storage_mib: u64,
 | 
			
		||||
    pub avail_mem_mb: u32,
 | 
			
		||||
    pub avail_vcpus: u32,
 | 
			
		||||
    pub avail_storage_gbs: u32,
 | 
			
		||||
    pub avail_ipv4: u32,
 | 
			
		||||
    pub avail_ipv6: u32,
 | 
			
		||||
    pub avail_ports: u32,
 | 
			
		||||
@ -106,15 +106,15 @@ impl VmNodeWithReports {
 | 
			
		||||
            avail_ipv4 >= {} &&
 | 
			
		||||
            avail_ipv6 >= {} &&
 | 
			
		||||
            avail_vcpus >= {} &&
 | 
			
		||||
            avail_mem_mib >= {} &&
 | 
			
		||||
            avail_storage_mib >= {}\n",
 | 
			
		||||
            avail_mem_mb >= {} &&
 | 
			
		||||
            avail_storage_gbs >= {}\n",
 | 
			
		||||
            filters.free_ports,
 | 
			
		||||
            filters.free_ports,
 | 
			
		||||
            filters.offers_ipv4 as u32,
 | 
			
		||||
            filters.offers_ipv6 as u32,
 | 
			
		||||
            filters.vcpus,
 | 
			
		||||
            filters.memory_mib,
 | 
			
		||||
            filters.storage_mib
 | 
			
		||||
            filters.memory_mb,
 | 
			
		||||
            filters.storage_gb
 | 
			
		||||
        );
 | 
			
		||||
        if !filters.city.is_empty() {
 | 
			
		||||
            query += &format!("&& city = '{}' ", filters.city);
 | 
			
		||||
@ -170,9 +170,9 @@ pub struct NewVmReq {
 | 
			
		||||
    pub extra_ports: Vec<u32>,
 | 
			
		||||
    pub public_ipv4: bool,
 | 
			
		||||
    pub public_ipv6: bool,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_url: String,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
@ -266,7 +266,7 @@ impl NewVmReq {
 | 
			
		||||
                    ->$new_vm_req
 | 
			
		||||
                    ->$vm_node
 | 
			
		||||
                CONTENT {{
 | 
			
		||||
                    created_at: time::now(), hostname: $hostname, vcpus: {}, memory_mib: {}, disk_size_mib: {},
 | 
			
		||||
                    created_at: time::now(), hostname: $hostname, vcpus: {}, memory_mb: {}, disk_size_gb: {},
 | 
			
		||||
                    extra_ports: {:?}, public_ipv4: {}, public_ipv6: {},
 | 
			
		||||
                    dtrfs_url: $dtrfs_url, dtrfs_sha: $dtrfs_sha, kernel_url: $kernel_url, kernel_sha: $kernel_sha,
 | 
			
		||||
                    price_per_unit: {}, locked_nano: {locked_nano}, error: ''
 | 
			
		||||
@ -274,8 +274,8 @@ impl NewVmReq {
 | 
			
		||||
            
 | 
			
		||||
            COMMIT TRANSACTION;",
 | 
			
		||||
            self.vcpus,
 | 
			
		||||
            self.memory_mib,
 | 
			
		||||
            self.disk_size_mib,
 | 
			
		||||
            self.memory_mb,
 | 
			
		||||
            self.disk_size_gb,
 | 
			
		||||
            self.extra_ports,
 | 
			
		||||
            self.public_ipv4,
 | 
			
		||||
            self.public_ipv6,
 | 
			
		||||
@ -334,7 +334,7 @@ impl WrappedMeasurement {
 | 
			
		||||
            _ => NEW_VM_REQ,
 | 
			
		||||
        };
 | 
			
		||||
        let mut resp = db
 | 
			
		||||
            .query(format!("live select error from {table} where id = {table}:{vm_id};"))
 | 
			
		||||
            .query(format!("live select error from {table} where id = {NEW_VM_REQ}:{vm_id};"))
 | 
			
		||||
            .query(format!(
 | 
			
		||||
                "live select * from measurement_args where id = measurement_args:{vm_id};"
 | 
			
		||||
            ))
 | 
			
		||||
@ -404,9 +404,9 @@ pub struct ActiveVm {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub public_ipv4: String,
 | 
			
		||||
    pub public_ipv6: String,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
@ -422,8 +422,8 @@ impl ActiveVm {
 | 
			
		||||
        // I tried, but this can be done better.
 | 
			
		||||
        // Storage cost should also be based on tier
 | 
			
		||||
        (self.vcpus as u64 * 10)
 | 
			
		||||
            + ((self.memory_mib + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_mib as u64 / 10)
 | 
			
		||||
            + ((self.memory_mb + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_gb as u64 / 10)
 | 
			
		||||
            + (!self.public_ipv4.is_empty() as u64 * 10)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -483,9 +483,9 @@ impl ActiveVm {
 | 
			
		||||
            mapped_ports,
 | 
			
		||||
            public_ipv4,
 | 
			
		||||
            public_ipv6,
 | 
			
		||||
            disk_size_mib: new_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: new_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: new_vm_req.vcpus,
 | 
			
		||||
            memory_mib: new_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: new_vm_req.memory_mb,
 | 
			
		||||
            dtrfs_sha: new_vm_req.dtrfs_sha,
 | 
			
		||||
            kernel_sha: new_vm_req.kernel_sha,
 | 
			
		||||
            created_at: new_vm_req.created_at.clone(),
 | 
			
		||||
@ -517,11 +517,11 @@ impl ActiveVm {
 | 
			
		||||
        if update_vm_req.vcpus > 0 {
 | 
			
		||||
            active_vm.vcpus = update_vm_req.vcpus;
 | 
			
		||||
        }
 | 
			
		||||
        if update_vm_req.memory_mib > 0 {
 | 
			
		||||
            active_vm.memory_mib = update_vm_req.memory_mib;
 | 
			
		||||
        if update_vm_req.memory_mb > 0 {
 | 
			
		||||
            active_vm.memory_mb = update_vm_req.memory_mb;
 | 
			
		||||
        }
 | 
			
		||||
        if update_vm_req.disk_size_mib > 0 {
 | 
			
		||||
            active_vm.disk_size_mib = update_vm_req.disk_size_mib;
 | 
			
		||||
        if update_vm_req.disk_size_gb > 0 {
 | 
			
		||||
            active_vm.disk_size_gb = update_vm_req.disk_size_gb;
 | 
			
		||||
        }
 | 
			
		||||
        if !update_vm_req.dtrfs_sha.is_empty() && !update_vm_req.kernel_sha.is_empty() {
 | 
			
		||||
            active_vm.dtrfs_sha = update_vm_req.dtrfs_sha;
 | 
			
		||||
@ -670,9 +670,9 @@ pub struct UpdateVmReq {
 | 
			
		||||
    pub admin: RecordId,
 | 
			
		||||
    #[serde(rename = "out")]
 | 
			
		||||
    pub vm_node: RecordId,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_url: String,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
@ -688,9 +688,9 @@ pub struct UpdateVmEvent {
 | 
			
		||||
    pub admin: RecordId,
 | 
			
		||||
    #[serde(rename = "out")]
 | 
			
		||||
    pub vm_node: RecordId,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_url: String,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
@ -704,9 +704,9 @@ impl From<UpdateVmReq> for UpdateVmEvent {
 | 
			
		||||
            vm_id: RecordId::from((VM_UPDATE_EVENT, update_vm_req.id.key().to_string())),
 | 
			
		||||
            admin: update_vm_req.admin,
 | 
			
		||||
            vm_node: update_vm_req.vm_node,
 | 
			
		||||
            disk_size_mib: update_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: update_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: update_vm_req.vcpus,
 | 
			
		||||
            memory_mib: update_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: update_vm_req.memory_mb,
 | 
			
		||||
            dtrfs_url: update_vm_req.dtrfs_url,
 | 
			
		||||
            dtrfs_sha: update_vm_req.dtrfs_sha,
 | 
			
		||||
            kernel_sha: update_vm_req.kernel_sha,
 | 
			
		||||
@ -743,32 +743,17 @@ impl UpdateVmReq {
 | 
			
		||||
            return Ok(None);
 | 
			
		||||
        }
 | 
			
		||||
        let contract = contract.unwrap();
 | 
			
		||||
        let mem_per_cpu = contract.memory_mib / contract.vcpus;
 | 
			
		||||
        let disk_per_cpu = contract.disk_size_mib / contract.vcpus;
 | 
			
		||||
        // this is needed cause TryFrom does not support await
 | 
			
		||||
        self.vm_node = contract.vm_node;
 | 
			
		||||
 | 
			
		||||
        if !((self.vcpus != 0 && contract.vcpus != self.vcpus)
 | 
			
		||||
            || (self.memory_mib != 0 && contract.memory_mib != self.memory_mib)
 | 
			
		||||
            || (self.memory_mb != 0 && contract.memory_mb != self.memory_mb)
 | 
			
		||||
            || (!self.dtrfs_sha.is_empty() && contract.dtrfs_sha != self.dtrfs_sha)
 | 
			
		||||
            || (self.disk_size_mib != 0 && contract.disk_size_mib != self.disk_size_mib))
 | 
			
		||||
            || (self.disk_size_gb != 0 && contract.disk_size_gb != self.disk_size_gb))
 | 
			
		||||
        {
 | 
			
		||||
            return Ok(Some(false));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Do not allow user to unbalance node resources
 | 
			
		||||
        if self.vcpus == 0 {
 | 
			
		||||
            self.vcpus = self.memory_mib / mem_per_cpu;
 | 
			
		||||
        }
 | 
			
		||||
        if self.memory_mib == 0 {
 | 
			
		||||
            self.memory_mib = self.vcpus * mem_per_cpu;
 | 
			
		||||
        }
 | 
			
		||||
        if self.vcpus == 0 {
 | 
			
		||||
            self.vcpus = self.disk_size_mib / disk_per_cpu;
 | 
			
		||||
        }
 | 
			
		||||
        if self.disk_size_mib == 0 {
 | 
			
		||||
            self.disk_size_mib = self.vcpus * disk_per_cpu;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let _: Vec<Self> = db.insert(UPDATE_VM_REQ).relation(self).await?;
 | 
			
		||||
        Ok(Some(true))
 | 
			
		||||
    }
 | 
			
		||||
@ -779,7 +764,6 @@ impl UpdateVmReq {
 | 
			
		||||
            error: String,
 | 
			
		||||
        }
 | 
			
		||||
        let _: Option<Self> = db.update((UPDATE_VM_REQ, id)).merge(UpdateVmError { error }).await?;
 | 
			
		||||
        let _: Option<Self> = db.delete((UPDATE_VM_REQ, id)).await?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -795,9 +779,9 @@ pub struct DeletedVm {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub public_ipv4: String,
 | 
			
		||||
    pub public_ipv6: String,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
@ -815,9 +799,9 @@ impl From<ActiveVm> for DeletedVm {
 | 
			
		||||
            mapped_ports: active_vm.mapped_ports,
 | 
			
		||||
            public_ipv4: active_vm.public_ipv4,
 | 
			
		||||
            public_ipv6: active_vm.public_ipv6,
 | 
			
		||||
            disk_size_mib: active_vm.disk_size_mib,
 | 
			
		||||
            disk_size_gb: active_vm.disk_size_gb,
 | 
			
		||||
            vcpus: active_vm.vcpus,
 | 
			
		||||
            memory_mib: active_vm.memory_mib,
 | 
			
		||||
            memory_mb: active_vm.memory_mb,
 | 
			
		||||
            dtrfs_sha: active_vm.dtrfs_sha,
 | 
			
		||||
            kernel_sha: active_vm.kernel_sha,
 | 
			
		||||
            created_at: active_vm.created_at,
 | 
			
		||||
@ -878,8 +862,8 @@ impl DeletedVm {
 | 
			
		||||
        // I tried, but this can be done better.
 | 
			
		||||
        // Storage cost should also be based on tier
 | 
			
		||||
        (self.vcpus as u64 * 10)
 | 
			
		||||
            + ((self.memory_mib + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_mib as u64 / 10)
 | 
			
		||||
            + ((self.memory_mb + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_gb as u64 / 10)
 | 
			
		||||
            + (!self.public_ipv4.is_empty() as u64 * 10)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -900,9 +884,9 @@ pub struct ActiveVmWithNode {
 | 
			
		||||
    pub mapped_ports: Vec<(u32, u32)>,
 | 
			
		||||
    pub public_ipv4: String,
 | 
			
		||||
    pub public_ipv6: String,
 | 
			
		||||
    pub disk_size_mib: u32,
 | 
			
		||||
    pub disk_size_gb: u32,
 | 
			
		||||
    pub vcpus: u32,
 | 
			
		||||
    pub memory_mib: u32,
 | 
			
		||||
    pub memory_mb: u32,
 | 
			
		||||
    pub dtrfs_sha: String,
 | 
			
		||||
    pub kernel_sha: String,
 | 
			
		||||
    pub created_at: Datetime,
 | 
			
		||||
@ -921,9 +905,9 @@ impl From<ActiveVmWithNode> for ActiveVm {
 | 
			
		||||
            mapped_ports: val.mapped_ports,
 | 
			
		||||
            public_ipv4: val.public_ipv4,
 | 
			
		||||
            public_ipv6: val.public_ipv6,
 | 
			
		||||
            disk_size_mib: val.disk_size_mib,
 | 
			
		||||
            disk_size_gb: val.disk_size_gb,
 | 
			
		||||
            vcpus: val.vcpus,
 | 
			
		||||
            memory_mib: val.memory_mib,
 | 
			
		||||
            memory_mb: val.memory_mb,
 | 
			
		||||
            dtrfs_sha: val.dtrfs_sha,
 | 
			
		||||
            kernel_sha: val.kernel_sha,
 | 
			
		||||
            created_at: val.created_at,
 | 
			
		||||
@ -990,8 +974,8 @@ impl ActiveVmWithNode {
 | 
			
		||||
        // I tried, but this can be done better.
 | 
			
		||||
        // Storage cost should also be based on tier
 | 
			
		||||
        (self.vcpus as u64 * 10)
 | 
			
		||||
            + ((self.memory_mib + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_mib as u64 / 1024 / 10)
 | 
			
		||||
            + ((self.memory_mb + 256) as u64 / 200)
 | 
			
		||||
            + (self.disk_size_gb as u64 / 10)
 | 
			
		||||
            + (!self.public_ipv4.is_empty() as u64 * 10)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1021,9 +1005,9 @@ impl From<&old_brain::BrainData> for Vec<VmNode> {
 | 
			
		||||
                region: old_node.region.clone(),
 | 
			
		||||
                city: old_node.city.clone(),
 | 
			
		||||
                ip: old_node.ip.clone(),
 | 
			
		||||
                avail_mem_mib: old_node.avail_mem_mb,
 | 
			
		||||
                avail_mem_mb: old_node.avail_mem_mb,
 | 
			
		||||
                avail_vcpus: old_node.avail_vcpus,
 | 
			
		||||
                avail_storage_mib: old_node.avail_storage_gbs * 1024,
 | 
			
		||||
                avail_storage_gbs: old_node.avail_storage_gbs,
 | 
			
		||||
                avail_ipv4: old_node.avail_ipv4,
 | 
			
		||||
                avail_ipv6: old_node.avail_ipv6,
 | 
			
		||||
                avail_ports: old_node.avail_ports,
 | 
			
		||||
@ -1053,9 +1037,9 @@ impl From<&old_brain::BrainData> for Vec<ActiveVm> {
 | 
			
		||||
                mapped_ports,
 | 
			
		||||
                public_ipv4: old_c.public_ipv4.clone(),
 | 
			
		||||
                public_ipv6: old_c.public_ipv6.clone(),
 | 
			
		||||
                disk_size_mib: old_c.disk_size_gb * 1024,
 | 
			
		||||
                disk_size_gb: old_c.disk_size_gb,
 | 
			
		||||
                vcpus: old_c.vcpus,
 | 
			
		||||
                memory_mib: old_c.memory_mb,
 | 
			
		||||
                memory_mb: old_c.memory_mb,
 | 
			
		||||
                dtrfs_sha: old_c.dtrfs_sha.clone(),
 | 
			
		||||
                kernel_sha: old_c.kernel_sha.clone(),
 | 
			
		||||
                price_per_unit: old_c.price_per_unit,
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@ use log::info;
 | 
			
		||||
use std::pin::Pin;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use surrealdb::engine::remote::ws::Client;
 | 
			
		||||
use surrealdb::{RecordId, Surreal};
 | 
			
		||||
use surrealdb::RecordId;
 | 
			
		||||
use surrealdb::Surreal;
 | 
			
		||||
use tokio::sync::mpsc;
 | 
			
		||||
use tokio_stream::wrappers::ReceiverStream;
 | 
			
		||||
use tokio_stream::{Stream, StreamExt};
 | 
			
		||||
@ -30,8 +31,8 @@ impl AppDaemonServer {
 | 
			
		||||
 | 
			
		||||
#[tonic::async_trait]
 | 
			
		||||
impl BrainAppDaemon for AppDaemonServer {
 | 
			
		||||
    type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessageApp, Status>> + Send>>;
 | 
			
		||||
    type RegisterAppNodeStream = Pin<Box<dyn Stream<Item = Result<DelAppReq, Status>> + Send>>;
 | 
			
		||||
    type BrainMessagesStream = Pin<Box<dyn Stream<Item = Result<BrainMessageApp, Status>> + Send>>;
 | 
			
		||||
 | 
			
		||||
    async fn register_app_node(
 | 
			
		||||
        &self,
 | 
			
		||||
@ -51,13 +52,12 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
			
		||||
            ip: req.main_ip,
 | 
			
		||||
            price: req.price,
 | 
			
		||||
 | 
			
		||||
            avail_mem_mib: 0,
 | 
			
		||||
            avail_mem_mb: 0,
 | 
			
		||||
            avail_vcpus: 0,
 | 
			
		||||
            avail_storage_mib: 0,
 | 
			
		||||
            avail_storage_gbs: 0,
 | 
			
		||||
            avail_ports: 0,
 | 
			
		||||
            max_ports_per_app: 0,
 | 
			
		||||
            disconnected_at: surrealdb::sql::Datetime::default(),
 | 
			
		||||
            connected_at: surrealdb::sql::Datetime::default(),
 | 
			
		||||
            offline_minutes: 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        app_node.register(&self.db).await?;
 | 
			
		||||
@ -89,7 +89,6 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        info!("App Daemon {} connected to receive brain messages", pubkey);
 | 
			
		||||
        let _ = db::AppNode::set_online(&self.db, &pubkey).await;
 | 
			
		||||
 | 
			
		||||
        let (tx, rx) = mpsc::channel(6);
 | 
			
		||||
        {
 | 
			
		||||
@ -163,8 +162,7 @@ impl BrainAppDaemon for AppDaemonServer {
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    log::warn!("App Daemon Disconnected: {e:?}");
 | 
			
		||||
                    let _ = db::AppNode::set_offline(&self.db, &pubkey).await;
 | 
			
		||||
                    log::warn!("App Daemon Disconnected: {e:?}")
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -115,7 +115,7 @@ impl BrainGeneralCli for GeneralCliServer {
 | 
			
		||||
        log::info!("Regitering new operator: {req:?}");
 | 
			
		||||
        match db::Account::operator_reg(&self.db, &req.pubkey, &req.email, req.escrow).await {
 | 
			
		||||
            Ok(()) => Ok(Response::new(Empty {})),
 | 
			
		||||
            Err(e) if matches!(e, db::Error::InsufficientFunds) => {
 | 
			
		||||
            Err(e) if matches!(e, db::Error::InsufficientFunds | db::Error::MinimalEscrow) => {
 | 
			
		||||
                Err(Status::failed_precondition(e.to_string()))
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
@ -133,7 +133,7 @@ impl BrainGeneralCli for GeneralCliServer {
 | 
			
		||||
        match db::kick_contract(&self.db, &req.operator_wallet, &req.contract_uuid, &req.reason)
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            Ok(nano_credits) => Ok(Response::new(KickResp { nano_credits })),
 | 
			
		||||
            Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })),
 | 
			
		||||
            Err(e)
 | 
			
		||||
                if matches!(
 | 
			
		||||
                    e,
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@
 | 
			
		||||
 | 
			
		||||
use crate::constants::{ACCOUNT, APP_NODE, ID_ALPHABET, NEW_APP_REQ, NEW_VM_REQ, VM_NODE};
 | 
			
		||||
use crate::db::prelude as db;
 | 
			
		||||
use detee_shared::app_proto::*;
 | 
			
		||||
use detee_shared::app_proto::AppNodeListResp;
 | 
			
		||||
use detee_shared::common_proto::MappedPort;
 | 
			
		||||
use detee_shared::general_proto::{Account, AccountBalance, ListOperatorsResp};
 | 
			
		||||
use detee_shared::vm_proto::*;
 | 
			
		||||
use detee_shared::{app_proto::*, vm_proto::*};
 | 
			
		||||
use nanoid::nanoid;
 | 
			
		||||
 | 
			
		||||
use surrealdb::RecordId;
 | 
			
		||||
@ -36,9 +36,9 @@ impl From<NewVmReq> for db::NewVmReq {
 | 
			
		||||
            extra_ports: new_vm_req.extra_ports,
 | 
			
		||||
            public_ipv4: new_vm_req.public_ipv4,
 | 
			
		||||
            public_ipv6: new_vm_req.public_ipv6,
 | 
			
		||||
            disk_size_mib: new_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: new_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: new_vm_req.vcpus,
 | 
			
		||||
            memory_mib: new_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: new_vm_req.memory_mb,
 | 
			
		||||
            kernel_url: new_vm_req.kernel_url,
 | 
			
		||||
            kernel_sha: new_vm_req.kernel_sha,
 | 
			
		||||
            dtrfs_url: new_vm_req.dtrfs_url,
 | 
			
		||||
@ -61,9 +61,9 @@ impl From<db::NewVmReq> for NewVmReq {
 | 
			
		||||
            extra_ports: new_vm_req.extra_ports,
 | 
			
		||||
            public_ipv4: new_vm_req.public_ipv4,
 | 
			
		||||
            public_ipv6: new_vm_req.public_ipv6,
 | 
			
		||||
            disk_size_mib: new_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: new_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: new_vm_req.vcpus,
 | 
			
		||||
            memory_mib: new_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: new_vm_req.memory_mb,
 | 
			
		||||
            kernel_url: new_vm_req.kernel_url,
 | 
			
		||||
            kernel_sha: new_vm_req.kernel_sha,
 | 
			
		||||
            dtrfs_url: new_vm_req.dtrfs_url,
 | 
			
		||||
@ -104,9 +104,9 @@ impl From<UpdateVmReq> for db::UpdateVmReq {
 | 
			
		||||
            admin: RecordId::from((ACCOUNT, new_vm_req.admin_pubkey)),
 | 
			
		||||
            // vm_node gets modified later, and only if the db::UpdateVmReq is required
 | 
			
		||||
            vm_node: RecordId::from((VM_NODE, String::new())),
 | 
			
		||||
            disk_size_mib: new_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: new_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: new_vm_req.vcpus,
 | 
			
		||||
            memory_mib: new_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: new_vm_req.memory_mb,
 | 
			
		||||
            kernel_url: new_vm_req.kernel_url,
 | 
			
		||||
            kernel_sha: new_vm_req.kernel_sha,
 | 
			
		||||
            dtrfs_url: new_vm_req.dtrfs_url,
 | 
			
		||||
@ -124,9 +124,9 @@ impl From<db::UpdateVmReq> for UpdateVmReq {
 | 
			
		||||
            // daemon does not care about VM hostname
 | 
			
		||||
            hostname: String::new(),
 | 
			
		||||
            admin_pubkey: update_vm_req.admin.key().to_string(),
 | 
			
		||||
            disk_size_mib: update_vm_req.disk_size_mib,
 | 
			
		||||
            disk_size_gb: update_vm_req.disk_size_gb,
 | 
			
		||||
            vcpus: update_vm_req.vcpus,
 | 
			
		||||
            memory_mib: update_vm_req.memory_mib,
 | 
			
		||||
            memory_mb: update_vm_req.memory_mb,
 | 
			
		||||
            kernel_url: update_vm_req.kernel_url,
 | 
			
		||||
            kernel_sha: update_vm_req.kernel_sha,
 | 
			
		||||
            dtrfs_url: update_vm_req.dtrfs_url,
 | 
			
		||||
@ -176,9 +176,9 @@ impl From<db::ActiveVmWithNode> for VmContract {
 | 
			
		||||
                "{}, {}, {}",
 | 
			
		||||
                db_c.vm_node.city, db_c.vm_node.region, db_c.vm_node.country
 | 
			
		||||
            ),
 | 
			
		||||
            memory_mb: db_c.memory_mib,
 | 
			
		||||
            memory_mb: db_c.memory_mb,
 | 
			
		||||
            vcpus: db_c.vcpus,
 | 
			
		||||
            disk_size_gb: db_c.disk_size_mib,
 | 
			
		||||
            disk_size_gb: db_c.disk_size_gb,
 | 
			
		||||
            mapped_ports: db_c
 | 
			
		||||
                .mapped_ports
 | 
			
		||||
                .iter()
 | 
			
		||||
@ -230,11 +230,6 @@ impl From<db::VmNodeWithReports> for VmNodeListResp {
 | 
			
		||||
            ip: vm_node.ip,
 | 
			
		||||
            reports: vm_node.reports.iter().map(|n| n.reason.clone()).collect(),
 | 
			
		||||
            price: vm_node.price,
 | 
			
		||||
            vcpus: vm_node.avail_vcpus,
 | 
			
		||||
            memory_mib: vm_node.avail_mem_mib,
 | 
			
		||||
            disk_mib: vm_node.avail_storage_mib,
 | 
			
		||||
            public_ipv4: vm_node.avail_ipv4 > 0,
 | 
			
		||||
            public_ipv6: vm_node.avail_ipv6 > 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -250,10 +245,6 @@ impl From<db::AppNodeWithReports> for AppNodeListResp {
 | 
			
		||||
            ip: app_node.ip,
 | 
			
		||||
            reports: app_node.reports.iter().map(|n| n.reason.clone()).collect(),
 | 
			
		||||
            price: app_node.price,
 | 
			
		||||
 | 
			
		||||
            vcpus: app_node.avail_vcpus as u64,
 | 
			
		||||
            memory_mib: app_node.avail_mem_mib as u64,
 | 
			
		||||
            disk_mib: app_node.avail_storage_mib as u64,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -261,9 +252,9 @@ impl From<db::AppNodeWithReports> for AppNodeListResp {
 | 
			
		||||
impl From<VmNodeResources> for db::VmNodeResources {
 | 
			
		||||
    fn from(res: VmNodeResources) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            avail_mem_mib: res.avail_memory_mib,
 | 
			
		||||
            avail_mem_mb: res.avail_memory_mb,
 | 
			
		||||
            avail_vcpus: res.avail_vcpus,
 | 
			
		||||
            avail_storage_mib: res.avail_storage_mib,
 | 
			
		||||
            avail_storage_gbs: res.avail_storage_gb,
 | 
			
		||||
            avail_ipv4: res.avail_ipv4,
 | 
			
		||||
            avail_ipv6: res.avail_ipv6,
 | 
			
		||||
            avail_ports: res.avail_ports,
 | 
			
		||||
@ -274,7 +265,6 @@ impl From<VmNodeResources> for db::VmNodeResources {
 | 
			
		||||
 | 
			
		||||
impl From<db::ActiveAppWithNode> for AppContract {
 | 
			
		||||
    fn from(value: db::ActiveAppWithNode) -> Self {
 | 
			
		||||
        let nano_per_minute = value.price_per_minute();
 | 
			
		||||
        let public_package_mr_enclave =
 | 
			
		||||
            Some(hex::decode(value.mr_enclave.clone()).unwrap_or_default());
 | 
			
		||||
 | 
			
		||||
@ -285,8 +275,8 @@ impl From<db::ActiveAppWithNode> for AppContract {
 | 
			
		||||
            node_pubkey: value.app_node.id.key().to_string(),
 | 
			
		||||
            public_ipv4: value.host_ipv4,
 | 
			
		||||
            resource: Some(AppResource {
 | 
			
		||||
                memory_mib: value.memory_mib,
 | 
			
		||||
                disk_size_mib: value.disk_size_mib,
 | 
			
		||||
                memory_mb: value.memory_mb,
 | 
			
		||||
                disk_size_gb: value.disk_size_gb,
 | 
			
		||||
                vcpus: value.vcpus,
 | 
			
		||||
                ports: value.mapped_ports.iter().map(|(_, g)| *g).collect(),
 | 
			
		||||
            }),
 | 
			
		||||
@ -298,7 +288,7 @@ impl From<db::ActiveAppWithNode> for AppContract {
 | 
			
		||||
 | 
			
		||||
            created_at: value.created_at.to_rfc3339(),
 | 
			
		||||
            updated_at: value.created_at.to_rfc3339(),
 | 
			
		||||
            nano_per_minute,
 | 
			
		||||
            nano_per_minute: value.price_per_unit,
 | 
			
		||||
            locked_nano: value.locked_nano,
 | 
			
		||||
            collected_at: value.collected_at.to_rfc3339(),
 | 
			
		||||
            hratls_pubkey: value.hratls_pubkey,
 | 
			
		||||
@ -327,9 +317,9 @@ impl From<NewAppReq> for db::NewAppReq {
 | 
			
		||||
            mr_enclave,
 | 
			
		||||
            hratls_pubkey: val.hratls_pubkey,
 | 
			
		||||
            ports: resource.ports,
 | 
			
		||||
            memory_mib: resource.memory_mib,
 | 
			
		||||
            memory_mb: resource.memory_mb,
 | 
			
		||||
            vcpus: resource.vcpus,
 | 
			
		||||
            disk_size_mib: resource.disk_size_mib,
 | 
			
		||||
            disk_size_gb: resource.disk_size_gb,
 | 
			
		||||
            locked_nano: val.locked_nano,
 | 
			
		||||
            price_per_unit: val.price_per_unit,
 | 
			
		||||
            error: String::new(),
 | 
			
		||||
@ -342,8 +332,8 @@ impl From<db::NewAppReq> for NewAppReq {
 | 
			
		||||
    fn from(value: db::NewAppReq) -> Self {
 | 
			
		||||
        let resource = AppResource {
 | 
			
		||||
            vcpus: value.vcpus,
 | 
			
		||||
            memory_mib: value.memory_mib,
 | 
			
		||||
            disk_size_mib: value.disk_size_mib,
 | 
			
		||||
            memory_mb: value.memory_mb,
 | 
			
		||||
            disk_size_gb: value.disk_size_gb,
 | 
			
		||||
            ports: value.ports,
 | 
			
		||||
        };
 | 
			
		||||
        let mr_enclave = Some(hex::decode(value.mr_enclave).unwrap_or_default());
 | 
			
		||||
@ -387,8 +377,8 @@ impl From<AppNodeResources> for db::AppNodeResources {
 | 
			
		||||
        Self {
 | 
			
		||||
            avail_ports: value.avail_no_of_port,
 | 
			
		||||
            avail_vcpus: value.avail_vcpus,
 | 
			
		||||
            avail_mem_mib: value.avail_memory_mib,
 | 
			
		||||
            avail_storage_mib: value.avail_storage_mib,
 | 
			
		||||
            avail_mem_mb: value.avail_memory_mb,
 | 
			
		||||
            avail_storage_gbs: value.avail_storage_gb,
 | 
			
		||||
            max_ports_per_app: value.max_ports_per_app,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -51,9 +51,9 @@ impl BrainVmDaemon for VmDaemonServer {
 | 
			
		||||
            city: req.city,
 | 
			
		||||
            ip: req.main_ip,
 | 
			
		||||
            price: req.price,
 | 
			
		||||
            avail_mem_mib: 0,
 | 
			
		||||
            avail_mem_mb: 0,
 | 
			
		||||
            avail_vcpus: 0,
 | 
			
		||||
            avail_storage_mib: 0,
 | 
			
		||||
            avail_storage_gbs: 0,
 | 
			
		||||
            avail_ipv4: 0,
 | 
			
		||||
            avail_ipv6: 0,
 | 
			
		||||
            avail_ports: 0,
 | 
			
		||||
@ -273,17 +273,10 @@ impl BrainVmCli for VmCliServer {
 | 
			
		||||
 | 
			
		||||
        let db_req: db::UpdateVmReq = req.clone().into();
 | 
			
		||||
 | 
			
		||||
        println!("The node is {}", db_req.vm_node);
 | 
			
		||||
 | 
			
		||||
        //  TODO: vm_node is not known at this point. It is populated by `request_hw_update`.
 | 
			
		||||
        //  As such, the pubsub node cannot be checked at this stage. This code should be moved,
 | 
			
		||||
        //  however we are not working on the redirect mechanic at the moment
 | 
			
		||||
        //
 | 
			
		||||
        //  if let Some(redirect) = db::check_pubsub_node(&self.db, db_req.vm_node.clone()).await? {
 | 
			
		||||
        //      log::info!("redirect: {redirect}");
 | 
			
		||||
        //      return Err(redirect);
 | 
			
		||||
        //  }
 | 
			
		||||
 | 
			
		||||
        if let Some(redirect) = db::check_pubsub_node(&self.db, db_req.vm_node.clone()).await? {
 | 
			
		||||
            log::info!("redirect: {redirect}");
 | 
			
		||||
            return Err(redirect);
 | 
			
		||||
        }
 | 
			
		||||
        let id = db_req.id.key().to_string();
 | 
			
		||||
 | 
			
		||||
        let mut hostname_changed = false;
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ DEFINE FUNCTION OVERWRITE fn::vm_price_per_minute(
 | 
			
		||||
    LET $vm = (select * from $vm_id)[0];
 | 
			
		||||
    LET $ip_price = IF $vm.public_ipv4.len() > 0 { 10 } ELSE { 0 };
 | 
			
		||||
    RETURN (
 | 
			
		||||
      ($vm.vcpus * 10) + (($vm.memory_mib + 256) / 200) + ($vm.disk_size_mib / 1024 / 10) + $ip_price)
 | 
			
		||||
      ($vm.vcpus * 10) + (($vm.memory_mb + 256) / 200) + ($vm.disk_size_gb / 10) + $ip_price)
 | 
			
		||||
    * $vm.price_per_unit;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -33,8 +33,8 @@ DEFINE FUNCTION OVERWRITE fn::app_price_per_minute(
 | 
			
		||||
    LET $app = (select * from $app_id)[0];
 | 
			
		||||
    RETURN 
 | 
			
		||||
     (($app.vcpus * 5) + 
 | 
			
		||||
        ($app.memory_mib / 200) + 
 | 
			
		||||
        ($app.disk_size_mib / 10))
 | 
			
		||||
        ($app.memory_mb / 200) + 
 | 
			
		||||
        ($app.disk_size_gb / 10))
 | 
			
		||||
    * $app.price_per_unit;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,9 +13,9 @@ DEFINE FIELD country ON TABLE vm_node TYPE string;
 | 
			
		||||
DEFINE FIELD region ON TABLE vm_node TYPE string;
 | 
			
		||||
DEFINE FIELD city ON TABLE vm_node TYPE string;
 | 
			
		||||
DEFINE FIELD ip ON TABLE vm_node TYPE string;
 | 
			
		||||
DEFINE FIELD avail_mem_mib ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_mem_mb ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_vcpus ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_storage_mib ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_storage_gbs ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_ipv4 ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_ipv6 ON TABLE vm_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_ports ON TABLE vm_node TYPE int;
 | 
			
		||||
@ -29,9 +29,9 @@ DEFINE FIELD hostname ON TABLE new_vm_req TYPE string;
 | 
			
		||||
DEFINE FIELD extra_ports ON TABLE new_vm_req TYPE array<int>;
 | 
			
		||||
DEFINE FIELD public_ipv4 ON TABLE new_vm_req TYPE bool;
 | 
			
		||||
DEFINE FIELD public_ipv6 ON TABLE new_vm_req TYPE bool;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE new_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE new_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE new_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE new_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE new_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD dtrfs_sha ON TABLE new_vm_req TYPE string;
 | 
			
		||||
DEFINE FIELD dtrfs_url ON TABLE new_vm_req TYPE string;
 | 
			
		||||
DEFINE FIELD kernel_sha ON TABLE new_vm_req TYPE string;
 | 
			
		||||
@ -46,9 +46,9 @@ DEFINE FIELD hostname ON TABLE active_vm TYPE string;
 | 
			
		||||
DEFINE FIELD mapped_ports ON TABLE active_vm TYPE array<[int, int]>;
 | 
			
		||||
DEFINE FIELD public_ipv4 ON TABLE active_vm TYPE string;
 | 
			
		||||
DEFINE FIELD public_ipv6 ON TABLE active_vm TYPE string;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE active_vm TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE active_vm TYPE int;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE active_vm TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE active_vm TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE active_vm TYPE int;
 | 
			
		||||
DEFINE FIELD dtrfs_sha ON TABLE active_vm TYPE string;
 | 
			
		||||
DEFINE FIELD kernel_sha ON TABLE active_vm TYPE string;
 | 
			
		||||
DEFINE FIELD created_at ON TABLE active_vm TYPE datetime;
 | 
			
		||||
@ -58,8 +58,8 @@ DEFINE FIELD collected_at ON TABLE active_vm TYPE datetime;
 | 
			
		||||
 | 
			
		||||
DEFINE TABLE update_vm_req TYPE RELATION FROM account TO vm_node SCHEMAFULL;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE update_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE update_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE update_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE update_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE update_vm_req TYPE int;
 | 
			
		||||
DEFINE FIELD dtrfs_sha ON TABLE update_vm_req TYPE string;
 | 
			
		||||
DEFINE FIELD dtrfs_url ON TABLE update_vm_req TYPE string;
 | 
			
		||||
DEFINE FIELD kernel_sha ON TABLE update_vm_req TYPE string;
 | 
			
		||||
@ -72,9 +72,9 @@ DEFINE FIELD hostname ON TABLE deleted_vm TYPE string;
 | 
			
		||||
DEFINE FIELD mapped_ports ON TABLE deleted_vm TYPE array<[int, int]>;
 | 
			
		||||
DEFINE FIELD public_ipv4 ON TABLE deleted_vm TYPE string;
 | 
			
		||||
DEFINE FIELD public_ipv6 ON TABLE deleted_vm TYPE string;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE deleted_vm TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE deleted_vm TYPE int;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE deleted_vm TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE deleted_vm TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE deleted_vm TYPE int;
 | 
			
		||||
DEFINE FIELD dtrfs_sha ON TABLE deleted_vm TYPE string;
 | 
			
		||||
DEFINE FIELD kernel_sha ON TABLE deleted_vm TYPE string;
 | 
			
		||||
DEFINE FIELD created_at ON TABLE deleted_vm TYPE datetime;
 | 
			
		||||
@ -88,14 +88,13 @@ DEFINE FIELD country ON TABLE app_node TYPE string;
 | 
			
		||||
DEFINE FIELD region ON TABLE app_node TYPE string;
 | 
			
		||||
DEFINE FIELD city ON TABLE app_node TYPE string;
 | 
			
		||||
DEFINE FIELD ip ON TABLE app_node TYPE string;
 | 
			
		||||
DEFINE FIELD avail_mem_mib ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_mem_mb ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_vcpus ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_storage_mib ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_storage_gbs ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD avail_ports ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD max_ports_per_app ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD price ON TABLE app_node TYPE int;
 | 
			
		||||
DEFINE FIELD connected_at ON TABLE app_node TYPE datetime;
 | 
			
		||||
DEFINE FIELD disconnected_at ON TABLE app_node TYPE datetime;
 | 
			
		||||
DEFINE FIELD offline_minutes ON TABLE app_node TYPE int;
 | 
			
		||||
 | 
			
		||||
DEFINE TABLE new_app_req Type RELATION FROM account to app_node SCHEMAFULL;
 | 
			
		||||
DEFINE FIELD app_name ON TABLE new_app_req TYPE string;
 | 
			
		||||
@ -103,9 +102,9 @@ DEFINE FIELD package_url ON TABLE new_app_req TYPE string;
 | 
			
		||||
DEFINE FIELD mr_enclave ON TABLE new_app_req TYPE string;
 | 
			
		||||
DEFINE FIELD hratls_pubkey ON TABLE new_app_req TYPE string;
 | 
			
		||||
DEFINE FIELD ports ON TABLE new_app_req TYPE array<int>;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD locked_nano ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD price_per_unit ON TABLE new_app_req TYPE int;
 | 
			
		||||
DEFINE FIELD error ON TABLE new_app_req TYPE string;
 | 
			
		||||
@ -116,8 +115,8 @@ DEFINE FIELD app_name ON TABLE active_app TYPE string;
 | 
			
		||||
DEFINE FIELD mapped_ports ON TABLE active_app TYPE array<[int, int]>;
 | 
			
		||||
DEFINE FIELD host_ipv4 ON TABLE active_app TYPE string;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_mib ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mb ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_gb ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD created_at ON TABLE active_app TYPE datetime;
 | 
			
		||||
DEFINE FIELD price_per_unit ON TABLE active_app TYPE int;
 | 
			
		||||
DEFINE FIELD locked_nano ON TABLE active_app TYPE int;
 | 
			
		||||
@ -131,8 +130,8 @@ DEFINE FIELD app_name ON TABLE deleted_app TYPE string;
 | 
			
		||||
DEFINE FIELD mapped_ports ON TABLE deleted_app TYPE array<[int, int]>;
 | 
			
		||||
DEFINE FIELD host_ipv4 ON TABLE deleted_app TYPE string;
 | 
			
		||||
DEFINE FIELD vcpus ON TABLE deleted_app TYPE int;
 | 
			
		||||
DEFINE FIELD memory_mib ON TABLE deleted_app TYPE int;
 | 
			
		||||
DEFINE FIELD disk_size_mib 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 created_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;
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,9 @@ FOR $contract IN (select * from active_vm fetch out) {
 | 
			
		||||
    } ELSE {
 | 
			
		||||
        $amount_due
 | 
			
		||||
    };
 | 
			
		||||
    LET $escrow_multiplier = IF $operator.escrow < 5_000_000_000_000 { 1 } ELSE { 5 };
 | 
			
		||||
    IF $node_is_online {
 | 
			
		||||
        UPDATE $operator.id SET balance += $amount_paid;
 | 
			
		||||
        UPDATE $operator.id SET balance += $amount_paid * $escrow_multiplier;
 | 
			
		||||
        UPDATE $contract.id SET
 | 
			
		||||
            locked_nano -= $amount_paid,
 | 
			
		||||
            collected_at = time::now();
 | 
			
		||||
@ -22,41 +23,11 @@ FOR $contract IN (select * from active_vm fetch out) {
 | 
			
		||||
            $amount_due
 | 
			
		||||
        };
 | 
			
		||||
        UPDATE $operator.id SET escrow -= $compensation;
 | 
			
		||||
        UPDATE $contract.id SET
 | 
			
		||||
            locked_nano += $compensation,
 | 
			
		||||
            collected_at = time::now();
 | 
			
		||||
        UPDATE $contract.in SET balance += $compensation;
 | 
			
		||||
    };
 | 
			
		||||
    IF $amount_paid >= $contract.locked_nano {
 | 
			
		||||
        fn::delete_vm($contract.id);
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FOR $app_contract IN (select * from active_app fetch out) {
 | 
			
		||||
    LET $operator = (select * from $app_contract.out.operator)[0];
 | 
			
		||||
    LET $node_is_online = $app_contract.out.connected_at > $app_contract.out.disconnected_at;
 | 
			
		||||
    LET $price_per_minute = fn::app_price_per_minute($app_contract.id);
 | 
			
		||||
    LET $amount_due = (time::now() - $app_contract.collected_at).mins() * $price_per_minute;
 | 
			
		||||
    LET $amount_paid = IF $amount_due > $app_contract.locked_nano {
 | 
			
		||||
        $app_contract.locked_nano
 | 
			
		||||
    } ELSE {
 | 
			
		||||
        $amount_due
 | 
			
		||||
    };
 | 
			
		||||
    LET $escrow_multiplier = IF $operator.escrow < 5_000_000_000_000 { 1 } ELSE { 5 };
 | 
			
		||||
    IF $node_is_online {
 | 
			
		||||
        UPDATE $operator.id SET balance += $amount_paid * $escrow_multiplier;
 | 
			
		||||
        UPDATE $app_contract.id SET
 | 
			
		||||
            locked_nano -= $amount_paid,
 | 
			
		||||
            collected_at = time::now();
 | 
			
		||||
    } ELSE {
 | 
			
		||||
        LET $compensation = IF $amount_due > $operator.escrow {
 | 
			
		||||
            $operator.escrow
 | 
			
		||||
        } ELSE {
 | 
			
		||||
            $amount_due
 | 
			
		||||
        };
 | 
			
		||||
        UPDATE $operator.id SET escrow -= $compensation;
 | 
			
		||||
        UPDATE $app_contract.in SET balance += $compensation;
 | 
			
		||||
    };
 | 
			
		||||
    IF $amount_paid >= $app_contract.locked_nano {
 | 
			
		||||
        fn::delete_app($app_contract.id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
-- TODO: implement for active_app
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
			
		||||
use detee_shared::app_proto::{AppResource, NewAppReq, NewAppRes};
 | 
			
		||||
use detee_shared::app_proto::{
 | 
			
		||||
    brain_app_cli_client::BrainAppCliClient, AppResource, NewAppReq, NewAppRes,
 | 
			
		||||
};
 | 
			
		||||
use tonic::transport::Channel;
 | 
			
		||||
 | 
			
		||||
use crate::common::test_utils::Key;
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use detee_shared::app_proto as sgx_proto;
 | 
			
		||||
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
 | 
			
		||||
use detee_shared::general_proto::AirdropReq;
 | 
			
		||||
use detee_shared::{app_proto, vm_proto};
 | 
			
		||||
use detee_shared::vm_proto as snp_proto;
 | 
			
		||||
use ed25519_dalek::{Signer, SigningKey};
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use rand::Rng;
 | 
			
		||||
@ -74,20 +75,20 @@ impl Key {
 | 
			
		||||
    pub fn sign_stream_auth_vm(
 | 
			
		||||
        &self,
 | 
			
		||||
        contracts: Vec<String>,
 | 
			
		||||
    ) -> Result<vm_proto::DaemonStreamAuth> {
 | 
			
		||||
    ) -> Result<snp_proto::DaemonStreamAuth> {
 | 
			
		||||
        let pubkey = self.pubkey.clone();
 | 
			
		||||
        let timestamp = chrono::Utc::now().to_rfc3339();
 | 
			
		||||
        let signature =
 | 
			
		||||
            self.try_sign_message(&(timestamp.to_string() + &format!("{contracts:?}")))?;
 | 
			
		||||
        Ok(vm_proto::DaemonStreamAuth { timestamp, pubkey, contracts, signature })
 | 
			
		||||
        Ok(snp_proto::DaemonStreamAuth { timestamp, pubkey, contracts, signature })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn sign_stream_auth_app(&self, contracts: Vec<String>) -> Result<app_proto::DaemonAuth> {
 | 
			
		||||
    pub fn sign_stream_auth_app(&self, contracts: Vec<String>) -> Result<sgx_proto::DaemonAuth> {
 | 
			
		||||
        let pubkey = self.pubkey.clone();
 | 
			
		||||
        let timestamp = chrono::Utc::now().to_rfc3339();
 | 
			
		||||
        let signature =
 | 
			
		||||
            self.try_sign_message(&(timestamp.to_string() + &format!("{contracts:?}")))?;
 | 
			
		||||
        Ok(app_proto::DaemonAuth { timestamp, pubkey, contracts, signature })
 | 
			
		||||
        Ok(sgx_proto::DaemonAuth { timestamp, pubkey, contracts, signature })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@
 | 
			
		||||
 | 
			
		||||
use super::test_utils::Key;
 | 
			
		||||
use anyhow::{anyhow, Result};
 | 
			
		||||
use detee_shared::app_proto;
 | 
			
		||||
use detee_shared::common_proto::Empty;
 | 
			
		||||
use detee_shared::general_proto::brain_general_cli_client::BrainGeneralCliClient;
 | 
			
		||||
use detee_shared::general_proto::{Account, RegOperatorReq, ReportNodeReq};
 | 
			
		||||
use detee_shared::vm_proto;
 | 
			
		||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
			
		||||
use detee_shared::{app_proto, vm_proto};
 | 
			
		||||
use futures::StreamExt;
 | 
			
		||||
use surreal_brain::constants::{ACTIVE_VM, NEW_VM_REQ};
 | 
			
		||||
use surreal_brain::db::prelude as db;
 | 
			
		||||
 | 
			
		||||
@ -9,25 +9,25 @@ async fn test_new_app_db_tx() {
 | 
			
		||||
    let db = prepare_test_db().await.unwrap();
 | 
			
		||||
 | 
			
		||||
    let req = NewAppReq {
 | 
			
		||||
        package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-04-16_21-59-38.tar.gz".to_string(),
 | 
			
		||||
        node_pubkey: "AH3SpV6ZjXMGSSe6xGH2ekUZxyUhnesAFz4LjX7PnvVn".to_string(),
 | 
			
		||||
        resource: Some(
 | 
			
		||||
            AppResource {
 | 
			
		||||
                memory_mib: 1500,
 | 
			
		||||
                disk_size_mib: 2000,
 | 
			
		||||
                vcpus: 1,
 | 
			
		||||
                ports: vec![ 8080 ],
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        uuid: "".to_string(),
 | 
			
		||||
        admin_pubkey: "H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc".to_string(),
 | 
			
		||||
        price_per_unit: 200000,
 | 
			
		||||
        locked_nano: 152400000,
 | 
			
		||||
        hratls_pubkey: "7E0F887AA6BB9104EEC1066F454D4C2D9063D676715F55F919D3FBCEDC63240B".to_string(),
 | 
			
		||||
        public_package_mr_enclave: Some(
 | 
			
		||||
            vec![ 128, 0, 97, 103, 165, 103, 68, 203, 240, 145, 153, 254, 34, 129, 75, 140, 8, 186, 63, 226, 144, 129, 201, 187, 175, 66, 80, 1, 151, 114, 183, 159, ],
 | 
			
		||||
        ),
 | 
			
		||||
        app_name: "lively-ferret".to_string(),
 | 
			
		||||
      package_url: "https://registry.detee.ltd/sgx/packages/actix-app-info_package_2025-04-16_21-59-38.tar.gz".to_string(),
 | 
			
		||||
      node_pubkey: "AH3SpV6ZjXMGSSe6xGH2ekUZxyUhnesAFz4LjX7PnvVn".to_string(),
 | 
			
		||||
      resource: Some(
 | 
			
		||||
          AppResource {
 | 
			
		||||
              memory_mb: 1500,
 | 
			
		||||
              disk_size_gb: 2,
 | 
			
		||||
              vcpus: 1,
 | 
			
		||||
              ports: vec![ 8080 ],
 | 
			
		||||
          },
 | 
			
		||||
      ),
 | 
			
		||||
      uuid: "".to_string(),
 | 
			
		||||
      admin_pubkey: "H21Shi4iE7vgfjWEQNvzmpmBMJSaiZ17PYUcdNoAoKNc".to_string(),
 | 
			
		||||
      price_per_unit: 200000,
 | 
			
		||||
      locked_nano: 152400000,
 | 
			
		||||
      hratls_pubkey: "7E0F887AA6BB9104EEC1066F454D4C2D9063D676715F55F919D3FBCEDC63240B".to_string(),
 | 
			
		||||
      public_package_mr_enclave: Some(
 | 
			
		||||
          vec![ 128, 0, 97, 103, 165, 103, 68, 203, 240, 145, 153, 254, 34, 129, 75, 140, 8, 186, 63, 226, 144, 129, 201, 187, 175, 66, 80, 1, 151, 114, 183, 159, ],
 | 
			
		||||
      ),
 | 
			
		||||
      app_name: "lively-ferret".to_string(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let db_req: db::NewAppReq = req.into();
 | 
			
		||||
 | 
			
		||||
@ -93,7 +93,6 @@ async fn test_app_creation() {
 | 
			
		||||
        db.select::<Option<db::ActiveApp>>((ACTIVE_APP, new_app_resp.uuid)).await.unwrap();
 | 
			
		||||
    assert!(active_app.is_some());
 | 
			
		||||
 | 
			
		||||
    tokio::time::sleep(std::time::Duration::from_millis(300)).await;
 | 
			
		||||
    let acc_db: db::Account = db.select((ACCOUNT, key.pubkey.clone())).await.unwrap().unwrap();
 | 
			
		||||
    assert_eq!(acc_db.balance, airdrop_amount * TOKEN_DECIMAL - (locking_nano + 100));
 | 
			
		||||
    assert_eq!(acc_db.tmp_locked, 0);
 | 
			
		||||
 | 
			
		||||
@ -102,8 +102,8 @@ async fn test_app_daemon_resource_msg() {
 | 
			
		||||
        node_pubkey: daemon_pubkey,
 | 
			
		||||
        avail_no_of_port: 5,
 | 
			
		||||
        avail_vcpus: 4,
 | 
			
		||||
        avail_memory_mib: 8192,
 | 
			
		||||
        avail_storage_mib: 10_0000,
 | 
			
		||||
        avail_memory_mb: 8192,
 | 
			
		||||
        avail_storage_gb: 100,
 | 
			
		||||
        max_ports_per_app: 5,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -123,17 +123,17 @@ async fn test_app_daemon_resource_msg() {
 | 
			
		||||
    let app_node_opt: Option<AppNode> = db.select((APP_NODE, daemon_key.pubkey)).await.unwrap();
 | 
			
		||||
    assert!(app_node_opt.is_some());
 | 
			
		||||
    let db::AppNode {
 | 
			
		||||
        avail_mem_mib,
 | 
			
		||||
        avail_mem_mb,
 | 
			
		||||
        avail_vcpus,
 | 
			
		||||
        avail_storage_mib,
 | 
			
		||||
        avail_storage_gbs,
 | 
			
		||||
        avail_ports,
 | 
			
		||||
        max_ports_per_app,
 | 
			
		||||
        ..
 | 
			
		||||
    } = app_node_opt.unwrap();
 | 
			
		||||
 | 
			
		||||
    assert_eq!(avail_mem_mib, req_data.avail_memory_mib);
 | 
			
		||||
    assert_eq!(avail_mem_mb, req_data.avail_memory_mb);
 | 
			
		||||
    assert_eq!(avail_vcpus, req_data.avail_vcpus);
 | 
			
		||||
    assert_eq!(avail_storage_mib, req_data.avail_storage_mib);
 | 
			
		||||
    assert_eq!(avail_storage_gbs, req_data.avail_storage_gb);
 | 
			
		||||
    assert_eq!(avail_ports, req_data.avail_no_of_port);
 | 
			
		||||
    assert_eq!(max_ports_per_app, req_data.max_ports_per_app);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,11 +3,12 @@
 | 
			
		||||
use common::prepare_test_env::{prepare_test_db, run_service_for_stream};
 | 
			
		||||
use common::test_utils::{airdrop, Key};
 | 
			
		||||
use common::vm_daemon_utils::register_vm_node;
 | 
			
		||||
use detee_shared::app_proto;
 | 
			
		||||
use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient;
 | 
			
		||||
use detee_shared::app_proto::brain_app_daemon_client::BrainAppDaemonClient;
 | 
			
		||||
use detee_shared::vm_proto;
 | 
			
		||||
use detee_shared::vm_proto::brain_vm_cli_client::BrainVmCliClient;
 | 
			
		||||
use detee_shared::vm_proto::brain_vm_daemon_client::BrainVmDaemonClient;
 | 
			
		||||
use detee_shared::{app_proto, vm_proto};
 | 
			
		||||
 | 
			
		||||
use crate::common::app_daemon_utils::register_app_node;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -91,8 +91,8 @@ async fn test_vm_daemon_resource_msg() {
 | 
			
		||||
        avail_ipv4: 2,
 | 
			
		||||
        avail_ipv6: 88,
 | 
			
		||||
        avail_vcpus: 4,
 | 
			
		||||
        avail_memory_mib: 8192,
 | 
			
		||||
        avail_storage_mib: 102400,
 | 
			
		||||
        avail_memory_mb: 8192,
 | 
			
		||||
        avail_storage_gb: 100,
 | 
			
		||||
        max_ports_per_vm: 5,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -114,9 +114,9 @@ async fn test_vm_daemon_resource_msg() {
 | 
			
		||||
    assert!(vm_node_opt.is_some());
 | 
			
		||||
 | 
			
		||||
    let db::VmNode {
 | 
			
		||||
        avail_mem_mib,
 | 
			
		||||
        avail_mem_mb,
 | 
			
		||||
        avail_vcpus,
 | 
			
		||||
        avail_storage_mib,
 | 
			
		||||
        avail_storage_gbs,
 | 
			
		||||
        avail_ports,
 | 
			
		||||
        avail_ipv4,
 | 
			
		||||
        avail_ipv6,
 | 
			
		||||
@ -124,9 +124,9 @@ async fn test_vm_daemon_resource_msg() {
 | 
			
		||||
        ..
 | 
			
		||||
    } = vm_node_opt.unwrap();
 | 
			
		||||
 | 
			
		||||
    assert_eq!(avail_mem_mib, req_data.avail_memory_mib);
 | 
			
		||||
    assert_eq!(avail_mem_mb, req_data.avail_memory_mb);
 | 
			
		||||
    assert_eq!(avail_vcpus, req_data.avail_vcpus);
 | 
			
		||||
    assert_eq!(avail_storage_mib, req_data.avail_storage_mib);
 | 
			
		||||
    assert_eq!(avail_storage_gbs, req_data.avail_storage_gb);
 | 
			
		||||
    assert_eq!(avail_ports, req_data.avail_ports);
 | 
			
		||||
    assert_eq!(avail_ipv4, req_data.avail_ipv4);
 | 
			
		||||
    assert_eq!(avail_ipv6, req_data.avail_ipv6);
 | 
			
		||||
 | 
			
		||||
@ -312,7 +312,7 @@ vm_contracts:
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 156.146.63.216
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
 | 
			
		||||
@ -329,7 +329,7 @@ vm_contracts:
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 173.234.136.154
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3ec4fc5aa5729f515967ec71be4a851622785c0080f7191b1b07717149840151
 | 
			
		||||
@ -347,7 +347,7 @@ vm_contracts:
 | 
			
		||||
      - 38288
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: 14e225e4aaf84cc2e0b5f64206121186ddebc4b378b886da3b2f7515dfd41692
 | 
			
		||||
@ -364,7 +364,7 @@ vm_contracts:
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 149.22.95.2
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: 3a68709138bed09c16671949cf1f03acee95a08381ba84fc70fb586001fa6767
 | 
			
		||||
@ -381,7 +381,7 @@ vm_contracts:
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 156.146.63.217
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 2
 | 
			
		||||
    memory_mb: 3000
 | 
			
		||||
    kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
 | 
			
		||||
@ -415,7 +415,7 @@ vm_contracts:
 | 
			
		||||
    exposed_ports: []
 | 
			
		||||
    public_ipv4: 149.36.48.100
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 4
 | 
			
		||||
    memory_mb: 4000
 | 
			
		||||
    kernel_sha: e49c8587287b21df7600c04326fd7393524453918c14d67f73757dc769a13542
 | 
			
		||||
@ -433,7 +433,7 @@ vm_contracts:
 | 
			
		||||
      - 46393
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
@ -452,7 +452,7 @@ vm_contracts:
 | 
			
		||||
      - 46393
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
@ -470,7 +470,7 @@ vm_contracts:
 | 
			
		||||
      - 46393
 | 
			
		||||
    public_ipv4: ""
 | 
			
		||||
    public_ipv6: ""
 | 
			
		||||
    disk_size_gb: 10240
 | 
			
		||||
    disk_size_gb: 10
 | 
			
		||||
    vcpus: 1
 | 
			
		||||
    memory_mb: 1000
 | 
			
		||||
    kernel_sha: e765e56166ef321b53399b9638584d1279821dbe3d46191c1f66bbaa075e7919
 | 
			
		||||
@ -480,7 +480,6 @@ vm_contracts:
 | 
			
		||||
    price_per_unit: 20000
 | 
			
		||||
    locked_nano: 12730960000
 | 
			
		||||
    collected_at: 2025-04-20T00:34:15.461240342Z
 | 
			
		||||
 | 
			
		||||
app_nodes:
 | 
			
		||||
  - node_pubkey: BiqoPUEoAxYxMRXUmyofoS9H1TBQgQqvLJ6MbWh88AQg
 | 
			
		||||
    operator_wallet: 7V3rEuh6j8VuwMVB5PyGqWKLmjJ4fYSv6WtrTL51NZTB
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user