Skip to content

Commit

Permalink
commit for updated PoR solution (#71)
Browse files Browse the repository at this point in the history
* commit for updated PoR solution

* fix some bugs and refine code according to review comments

* optimize circuit by only hashing necessary assets user owns

* fix the bug introduced by unordered map

* change VipLoan to Loan and format codes

* return error when there are invalid accounts

* update gnark version and refine some logs

* change monitor time of script from 2m to 5m

* add exponentialBackOff for prover getting redis lock

* add the technical details of circuit

* refactor circuit test codes
  • Loading branch information
lightning-li authored Sep 29, 2024
1 parent 9c5f901 commit 5d26d4f
Show file tree
Hide file tree
Showing 38 changed files with 3,857 additions and 915 deletions.
64 changes: 29 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# zkmerkle-proof-of-solvency
## Circuit Design

See the [technical blog](https://gusty-radon-13b.notion.site/Proof-of-solvency-61414c3f7c1e46c5baec32b9491b2b3d) for more details about background and circuit design
See the [technical blog](./docs/updated_proof_of_solvency_to_mitigate_dummy_user_attack.md) for more details about background and circuit design
## How to run

### Run third-party services
Expand All @@ -17,18 +17,15 @@ docker run -d --name zkpos-redis -p 6379:6379 redis

docker run -d --name zkpos-mysql -p 3306:3306 -v /server/docker_data/mysql_data:/var/lib/mysql -e MYSQL_USER=zkpos -e MYSQL_PASSWORD=zkpos@123 -e MYSQL_DATABASE=zkpos -e MYSQL_ROOT_PASSWORD=zkpos@123 mysql

docker run -d --name zkpos-kvrocks -p 6666:6666 -v /server/docker_data/kvrocksdata:/var/lib/kvrocks apache/kvrocks
docker run -d --name zkpos-kvrocks -p 6666:6666 -v /server/docker_data/kvrocksdata:/kvrocksdata apache/kvrocks --dir /kvrocksdata
```

where `/server/docker_data/` is directory in the host machine which is used to persist mysql and kvrocks docker data.


### Generate zk keys

The `keygen` service is for generating zk related keys which are used to generate and verify zk proof. The `BatchCreateUserOpsCounts` constant variable in utils package represent how many users can be created in one batch.
The larger the `BatchCreateUserOpsCounts` is, the longer it will take to generate zk-related keys and generate zk proof.

We choose `864` as the `BatchCreateUserOpsCounts` variable. It will take about 6 hours to generate zk-related keys, and 105 seconds to generate zk proof for one batch in a 128GB memory and 32 core virtual machine.
The `keygen` service is for generating zk related keys which are used to generate and verify zk proof. The updated PoR solution now supports multi-tier circuits based on the counts of asset types a user owns. The `BatchCreateUserOpsCountsTiers` constant in the utils package represents the multi-tier circuit configuration that defines how many users can be created in one batch for each specific tier.

Run the following commands to start `keygen` service:
```
Expand All @@ -39,16 +36,12 @@ cd src/keygen; go run main.go

After `keygen` service finishes running, there will be several key files generated in the current directory, like the following:
```shell
Total 26G
-rw-rw-r-- 1 ec2-user ec2-user 69M 12月 26 07:49 zkpor864.ccs.ct.save
-rw-rw-r-- 1 ec2-user ec2-user 16G 12月 26 07:51 zkpor864.ccs.save
-rw-rw-r-- 1 ec2-user ec2-user 1.8G 12月 26 07:51 zkpor864.pk.A.save
-rw-rw-r-- 1 ec2-user ec2-user 1.6G 12月 26 07:51 zkpor864.pk.B1.save
-rw-rw-r-- 1 ec2-user ec2-user 3.2G 12月 26 07:51 zkpor864.pk.B2.save
-rw-rw-r-- 1 ec2-user ec2-user 59M 12月 26 07:51 zkpor864.pk.E.save
-rw-rw-r-- 1 ec2-user ec2-user 1.9G 12月 26 07:52 zkpor864.pk.K.save
-rw-rw-r-- 1 ec2-user ec2-user 708 12月 26 07:52 zkpor864.vk.save
-rw-rw-r-- 1 ec2-user ec2-user 2.1G 12月 26 07:52 zkpor864.pk.Z.save
-rw-r--r--. 1 root root 524 Aug 19 09:46 zkpor350_128.vk
-rw-r--r--. 1 root root 12G Aug 19 09:46 zkpor350_128.pk
-rw-r--r--. 1 root root 7.5G Aug 19 09:47 zkpor350_128.r1cs
-rw-r--r--. 1 root root 524 Aug 19 10:38 zkpor50_580.vk
-rw-r--r--. 1 root root 12G Aug 19 10:38 zkpor50_580.pk
-rw-r--r--. 1 root root 12G Aug 19 10:39 zkpor50_580.r1cs
```

### Generate witness
Expand Down Expand Up @@ -88,7 +81,7 @@ cd witness; go run main.go

The `witness` service supports recovery from unexpected crash. After `witness` service finish running, we can see `witness` from `witness` table.

The performance: about 850 users witness generation per second in a 128GB memory and 32 core virtual machine.
One witness batch contains 700 users whose assets number is less or equal than 50, and 92 users whose assets number is larger than 50.

### Generate zk proof

Expand All @@ -103,7 +96,8 @@ The `prover` service is used to generate zk proof and supports running in parall
"Host": "127.0.0.1:6379",
"Type": "node"
},
"ZkKeyName": "/server/zkmerkle-proof-of-solvency/src/keygen/zkpor864"
"ZkKeyName": ["/server/zkmerkle-proof-of-solvency/src/keygen/zkpor50_580", "/server/zkmerkle-proof-of-solvency/src/keygen/zkpor350_128"],
"AssetsCountTiers": [50, 350]
}
```

Expand All @@ -114,7 +108,8 @@ Where
- `Redis`:
- `Host`: `redis` service listen addr;
- `Type`: only support `node` type
- `ZkKeyName`: the key name generated by `keygen` service
- `ZkKeyName`: the list of key names generated by `keygen` service
- `AssetsCountTiers`: The list of asset count tiers, each corresponding to a key name in `ZkKeyName`

Run the following command to start `prover` service:
```shell
Expand Down Expand Up @@ -172,13 +167,15 @@ The service use `config.json` as its config file, and the sample config is as fo
```json
{
"ProofTable": "config/proof.csv",
"ZkKeyName": "config/zkpor864",
"ZkKeyName": ["config/zkpor50_580", "config/zkpor350_128"],
"AssetsCountTiers": [50, 350],
"CexAssetsInfo": [{"TotalEquity":219971568487,"TotalDebt":9789219,"BasePrice":24620000000},{"TotalEquity":8664493444,"TotalDebt":122580,"BasePrice":1682628000000},{"TotalEquity":67463930749983,"TotalDebt":16127314913,"BasePrice":100000000},{"TotalEquity":68358645578,"TotalDebt":130187,"BasePrice":121377000000},{"TotalEquity":590353015932,"TotalDebt":0,"BasePrice":598900000},{"TotalEquity":255845425858,"TotalDebt":13839361,"BasePrice":6541000000},{"TotalEquity":0,"TotalDebt":0,"BasePrice":99991478},{"TotalEquity":267958065914051,"TotalDebt":501899265949,"BasePrice":100000000},{"TotalEquity":124934670143615,"TotalDebt":1422964747,"BasePrice":34500000}]
}
```
Where
- `ProofTable`: this is proof csv file which can be exported by `proof` table;
- `ZkKeyName`: the key name generated by `keygen` service;
- `AssetsCountTiers`: The list of asset count tiers, each corresponding to a key name in `ZkKeyName`;
- `CexAssetsInfo`: this is published by CEX, it represents CEX's liability;

You can get `CexAssetsInfo` using `dbtool` command after `witness` service run finished. Run the following command to verify batch proof:
Expand All @@ -189,15 +186,7 @@ cd verifier; go run main.go
#### Verify user proof
The service use `user_config.json` as its config file, and the sample config is as follows:
```json
{
"AccountIndex": 9,
"AccountIdHash": "0000041cb7323211d0b356c2fe6e79fdaf0c27d74b3bb1a4635942f9ae92145b",
"Root": "29591ef3a9ed02605edd6ab14f5dd49e7dbe0d03e72a27383f929ef3efb7514f",
"Assets": [{"Index":7,"Equity":123456000,"Debt":0}],
"Proof": ["DrPpFsm4/5HntRTf8M3dbgpdrxq3Q8lZkB2ngysW2js=","G1WgD/CvmGApQgmIX0rE0BlSifkw6IfNwY9z2DnRazM=","HZm8N563lDMrx//oMjejlXKLzLrZQRqKZKyXwpDnT+I=","A+wqmnw0NfdgAyEieZRqKlczF48VOROxME36YBwLhmY=","BaLA62VkWlLE/FZTxnvx/lwU7WNfDxgdM2cBw27MAog=","EvkbbZF7Y/W8AxPc+49lmzzFNdyPl1QWRu1ZQB/gmz8=","EJzsNkrzgcB6LIctzoqWAetzLHO57vx00FxIlLKhwqg=","D3kGOz1Xcsi5hGXr02LOSC23L+lCOhq6FlXGiPYcYig=","DSAmcCy6GEl1DlRNpP05e4I9ScMCz/4DtJCKpserVL8=","L16LdkqEmjI/4uVNETm4ScZ5uA/Cho59zjbgN1OgI+k=","CaRuyDB3b3JeZlItZw8Txi7MSP5vyRpco0OtHRuO6RQ=","CkfKeaCV6rLcskjWE91vCAxTPKEymsDtJvc4r8aWytw=","JfAF+uLGIBAJklZrWRPjxmJ3lFHyau9oNL5dOwQ72kQ=","JKQm66yeIFuPJcm5OkTUDyohsL5CWFF+fFpW/NiS2O0=","KXs+zCQELaQRJzQoCnYm+G2lr5eKLqmWd3G0xeSPWgc=","AFL9l/1p5puhKsCtS7WTT/hExtl3hmRfXnTofVY9+3s=","A2lctbb1mGsAgbERpnu4/RKX/OkcU06dhU9l4wS7e8k=","AIB1T+2rEytbSyMLfyp1rNhS0RCmPYwITdjhb/34FVQ=","GQmXAAvuoPUvt4zDrQ9qaAcRV5t8TPFXAIAIuwv0vr0=","J8pP9A0l54qj9UfumcTXn3hVBYEh+iBH03newr296io=","LD/99JpY8ZZupXaoRt6p6wKDmQepQyVMsJ3s5rX+Q9g=","EOqvnEUbpnzF0HeEv0PdB/R3KMbNU15jYqwNaBJ/j7M=","KLZwBqvYBNFPBFVPQQOipuYd9bYdLEme+Y5UiDRV5Z8=","IXgr/ZWOF/rduJvkSjOABCUtj5C1+tXjHJ/AwR+f7MM=","MFzAvInNDNdT4+6kp2YKAUT4+sb8fdrha9BxXnwHR1Q=","DdvOYaMZDO/di7mBvQdEocS2CE8BH2bGmIDuSGBaHa8=","MEa67EULCikf5rusfcsUb/kWUfx7NPpHjzHKEo3imho=","KLRU4kqn5Fd3FtjapW9MTJBgWdMtAGKgt3OVLQNHh14="],
"TotalEquity": 123456000,
"TotalDebt": 0
}
{"AccountIndex":9,"AccountIdHash":"000000000000000000000000000000000000000000000000000000000000006d","TotalEquity":107595993240612342000000,"TotalDebt":4812541145779934000000,"TotalCollateral":4861152676874104600000,"Assets":[{"Index":0,"Equity":14571647457,"Debt":184812783,"Loan":7285823729,"Margin":3642911864,"PortfolioMargin":1821455932},{"Index":1,"Equity":25424316291,"Debt":3323064077,"Loan":12712158145,"Margin":6356079073,"PortfolioMargin":3178039536},{"Index":2,"Equity":57834282404,"Debt":19716095367,"Loan":28917141202,"Margin":14458570601,"PortfolioMargin":7229285300},{"Index":3,"Equity":25100,"Debt":669524367015,"Loan":12550,"Margin":6275,"PortfolioMargin":3138}],"Root":"1a4940fecdbf2f7d8fe9c4f16083ceb587f69f0b9af0d02d528235757536668f","Proof":["EerEdgizAIY2QB/1c7e3vogBKXoD3Q3WN+wDO/hx/HY=","Kj6yinCJObEjIDqK3KPiXqGUetaaHdYoP6WRVWRyubE=","JxQCfxGWwtk0XQi2UkU4GUjHZKmW5uCQw0Unqf6nJUI=","CfqgZ96f0N0RUyd4IQ1sEdsm2Yq+4WRCq7awff2P1q8=","LvSjy7ocJKqWPpjRr17niwhgtmqNFMNuLS8lVLRWLbo=","EWnMgwIncL2h5IMqlObRbaa0hD2DMWcbNPuSLrb+LwY=","HiOSZAFdHtBMxcPB4yWGPY9dTuHSLMCzAOsoh4qt+VI=","EcAo/cipNXN6IeLHoQ+V9ZDX23KqZhF7lp65zJoo7MU=","EXs4mjwX3UpfJxC8Kbyey3JEyxilg8FXXUGabXvApac=","DBGelh5dqSIf/6qrFwCud4VSt77d0MMdmq41g78dmwc=","I4HkTsZT2BLXNzJCXW15MbQ8MDtzXjbbfJsZ15ZczS0=","FmFiP3/04HxlH5/MJeRG1SbSzu9OQVzJM49uQO10w1o=","C28Jko6/+VPAikr9oK2vf9jbCVhVDjWG6r699bHv+Vk=","Jm8aL9AJ54lAZRMbySEmEH8oAKiEp7jlOI2wOnu4KRo=","GdbpvwyPyQb6/HOZs17w6AMncy/htlh4R/dXIdyJv5w=","IeDs6wpjmp+DbYopQmas2GMl8CZpA+sqr9/+lzRvBZQ=","AD+yl4nRexwrClLzFeHozdiNJCcn/I1+RYKAHwWjS1k=","GdGGEDCn9AHLU8bC6QsDzqCF0F6FrVGq/DbA0jdsdHg=","JOxehD0Ia2qECvgPvgPIKzre8/cQHN9MO2g4fp1yR/k=","G/rWV3lgtPIpEYF5YPJKfzOsHOIGjaMkj+Jl5+W/Vs4=","FkShbCYN5Dmq5ePg/edPHJsgCkDWa5sbttdOntkfrs8=","Fw4CMs3uC4DLmXzr+1Z8YL5nifrZ28ERj7PJmKOAyjc=","G7sBVubhUFfBP7dPh1j5pJHUQKgIt8Urv8uKSlmDIfw=","H68ykCMipvlmIvsqggAZdTN2sVuURSsZjT62jaC7yw4=","L+fBG2iAWzztMIp9v/FVKvmA32J5y/xyK+Gkfk6/7oc=","IHcZ3Kq0U/3YtilfJZnfL3lBZZ7vF6UXDWC+YQjx9bw=","BOc4UULtPNPKmGuvrWUC5oQcEw1UoytqQRbtqRg/+E0=","F/aouPJyLNduMVnva1aMSV04QPRc0MhDhgTP2/L0ZKs="]}
```

Where
Expand All @@ -209,6 +198,7 @@ Where
- `Proof`: user merkle proof which uses `base64` encoding;
- `TotalEquity`: user total equity which is calculated by all the assets equity multipy its corresponding price
- `TotalDebt`: user total debt which is calculated by all the assets debt multipy its corresponding price
- `Loan/Margin/PortfolioMargin`: user collateral value

Run the following command to verify single user proof:
```shell
Expand All @@ -232,6 +222,16 @@ Run the following command to get cex assets info in json format:
cd src/dbtool; go run main.go -query_cex_assets
```

Run the following command to query user config which is used in verifier:
```shell
cd src/dbtool; go run main.go -query_account_data 9
```

Run the following command to query witness data which is the input of circuit:
```shell
cd src/dbtool; go run main.go -query_witness_data 9
```

### Check data correctness

#### check account tree construct correctness
Expand All @@ -246,9 +246,3 @@ cd userproof; go run main.go -memory_tree
Compare the account tree root in the output log with the account tree root by `witness` service, if matches, then the account tree is correctly constructed.

**Note: when `userproof` service runs in the `-memory_tree` mode, its performance is about 75k per minute, so 3000w accounts will take about ~7 hours**

#### check mysql table consistency

Suppose the number of users is `accountsNum`, and `batchNumber` is 864, so the number of rows in `witness` and `proof` table is: `(accountNum + 864 - 1) / 864`. And the number of rows in `userproof` table equals to `accountsNum`.

When all services run finished, Check that the number of rows in table is as expected.
2 changes: 1 addition & 1 deletion check_prover_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def rerun():

rerun_retry = 0
while True:
time.sleep(2*60)
time.sleep(5*60)
cur_delta = get_delta()
if prev_delta == 0 or cur_delta == 0:
print("all proofs has been generated")
Expand Down
Loading

0 comments on commit 5d26d4f

Please sign in to comment.