-
Notifications
You must be signed in to change notification settings - Fork 0
Improve deanonymization functionalities wasm #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1c8fe47
840ebac
00cc25c
daf9ab3
2f80bc3
47e24d9
990233d
ca755cb
0fde49c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,24 @@ import ( | |
|
|
||
| // --- High-Level Application Logic --- | ||
|
|
||
| // recordTransaction appends a transaction record to the state's transaction log. | ||
| // Must be called after state.Nonce++ so the nonce matches the corresponding event. | ||
| func recordTransaction(state *ApplicationInternalState, txType string, from, to types.Address, amount *types.Uint256, invoiceID string) { | ||
| amountCopy := *amount | ||
| state.Transactions = append(state.Transactions, TransactionRecord{ | ||
alsala marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Type: txType, | ||
| From: from, | ||
| To: to, | ||
| Amount: &amountCopy, | ||
| Nonce: state.Nonce, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be useful to have a timestamp or a way to retrieve a timestamp from the Nonce
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i added a timestamp |
||
| Timestamp: Now(), | ||
| InvoiceID: invoiceID, | ||
| }) | ||
| if len(state.Transactions) > MaxTransactions { | ||
| state.Transactions = state.Transactions[len(state.Transactions)-MaxTransactions:] | ||
| } | ||
| } | ||
|
|
||
| func LoadModule(appId int64) types.LoadModuleResult { | ||
| initialState := &ApplicationInternalState{ | ||
| AppID: uint64(appId), | ||
|
|
@@ -74,6 +92,7 @@ func DepositFunds(senderPtr *types.Address, value *types.Uint256, stateJSON stri | |
| return types.DepositResult{Error: fmt.Sprintf("Overflow while adding amount %s to balance: %s", value, oldBalance)} | ||
| } | ||
| currentState.Nonce++ | ||
| recordTransaction(¤tState, "deposit", *senderPtr, *senderPtr, value, "") | ||
|
|
||
| // Create deposit event | ||
| eventData := DepositEvent{ | ||
|
|
@@ -204,6 +223,7 @@ func ProcessRequest(senderPtr *types.Address, requestType int32, payloadJSON, st | |
| instructions.Transfer.Amount, oldRecipientBalance)} | ||
| } | ||
| currentState.Nonce++ | ||
| recordTransaction(¤tState, "transfer", sender, instructions.Transfer.To, instructions.Transfer.Amount, instructions.Transfer.InvoiceID) | ||
|
|
||
| // Create events for both parties | ||
| senderEventData := SenderEvent{ | ||
|
|
@@ -270,6 +290,7 @@ func ProcessRequest(senderPtr *types.Address, requestType int32, payloadJSON, st | |
| // Execute withdrawal | ||
| currentState.Accounts[senderHex].Balance.Sub(*currentState.Accounts[senderHex].Balance, *instructions.Withdraw.Amount) | ||
| currentState.Nonce++ | ||
| recordTransaction(¤tState, "withdrawal", sender, instructions.Withdraw.To, instructions.Withdraw.Amount, "") | ||
|
|
||
| // Create withdrawal | ||
| withdrawals = append(withdrawals, types.Withdrawal{ | ||
|
|
@@ -298,23 +319,69 @@ func ProcessRequest(senderPtr *types.Address, requestType int32, payloadJSON, st | |
| }) | ||
|
|
||
| case "deanonymize": | ||
| // Generate deanonymization report | ||
| report := DeanonymizationReport{ | ||
| Accounts: currentState.Accounts, | ||
| Nonce: currentState.Nonce, | ||
| reportType := "balances" | ||
| if instructions.Deanonymize != nil && instructions.Deanonymize.ReportType != "" { | ||
| reportType = instructions.Deanonymize.ReportType | ||
| } | ||
|
|
||
| var reportBytes []byte | ||
| var err error | ||
|
|
||
| switch reportType { | ||
| case "balances": | ||
| reportBytes, err = json.Marshal(DeanonymizationReport{ | ||
| Accounts: currentState.Accounts, | ||
| Nonce: currentState.Nonce, | ||
| }) | ||
| case "tx_history": | ||
| if instructions.Deanonymize.Address.IsZero() { | ||
| return types.ProcessResult{Error: "tx_history report requires a non-zero address"} | ||
| } | ||
| addr := instructions.Deanonymize.Address | ||
| addrHex := addr.Hex() | ||
| fromTs := instructions.Deanonymize.FromTimestamp | ||
| toTs := instructions.Deanonymize.ToTimestamp | ||
|
|
||
| filtered := []TransactionRecord{} | ||
| for _, tx := range currentState.Transactions { | ||
| if tx.From != addr && tx.To != addr { | ||
| continue | ||
| } | ||
| if fromTs > 0 && tx.Timestamp < fromTs { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering the way currentState.Transactions is implemented, the transactions should be ordered by timestamp, so the loop could be stopped the moment the transactions timestamps are outside the requested range
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| continue | ||
| } | ||
| if toTs > 0 && tx.Timestamp > toTs { | ||
| break | ||
| } | ||
| filtered = append(filtered, tx) | ||
| } | ||
|
|
||
| // Look up current balance for the requested address | ||
| var balance *types.Uint256 | ||
| if acc := currentState.Accounts[addrHex]; acc != nil { | ||
| balance = acc.Balance | ||
| } else { | ||
| balance = types.NewUint256(0) | ||
| } | ||
|
|
||
| reportBytes, err = json.Marshal(TxHistoryReport{ | ||
| Address: addr, | ||
| Balance: balance, | ||
| Transactions: filtered, | ||
| }) | ||
| default: | ||
| return types.ProcessResult{Error: fmt.Sprintf("Unsupported report type: %s", reportType)} | ||
| } | ||
|
|
||
| // Serialize the report | ||
| reportBytes, err := json.Marshal(report) | ||
| if err != nil { | ||
| utils.LogError("ProcessRequest: failed to serialize deanonymization report: %v", err) | ||
| return types.ProcessResult{Error: fmt.Sprintf("Failed to serialize deanonymization report: %v", err)} | ||
| utils.LogError("ProcessRequest: failed to serialize %s report: %v", reportType, err) | ||
| return types.ProcessResult{Error: fmt.Sprintf("Failed to serialize %s report: %v", reportType, err)} | ||
| } | ||
|
|
||
| utils.LogDebug("ProcessRequest: deanonymize sender=%s, accountsCount=%d, reportSize=%d", | ||
| senderHex, len(currentState.Accounts), len(reportBytes)) | ||
| utils.LogDebug("ProcessRequest: deanonymize sender=%s, reportType=%s, reportSize=%d", | ||
| senderHex, reportType, len(reportBytes)) | ||
| return types.ProcessResult{ | ||
| State: []byte(stateJSON), //we have not modified the app state, using the old one to avoid useless marshalling | ||
| State: []byte(stateJSON), | ||
| Report: reportBytes, | ||
| Fuel: types.NewUint256(20), | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state.Transactions will grow indefinetely and it will be a problem to manage a state too big. We need or to put a cap on the number of transactions saved and discard the oldest ones or we need to implement in Vela a way to manage big states. @paolocappelletti what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would postpone to next impromevements.
Long term goal: the state should not be passed entirely to the wasm, but only accessed "on-request": the wasm interface should provide more low level primitives. es: a key-value access with methods get(key) set(key,value). then there will be a protocol for handling the call: executor -> encryption/decryption of the value -> manager -> db (commit only upon success of the request).
(This will allow also to charge fees for storage access/update as solidity does)
Will add some tickets in the backlog!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add anyway a simple check that prevents that the list of transactions becomes too big, in the meantime we develop a better solution. Just to be on the safer side...
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok seems reasonable.
let's add a max size constant @andreanistico (50?) and keep always the more recents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a MaxTransactions constant and trim the state to that length, keeping the most recent