Skip to content
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

Algod: Add experimental endpoint for simulating transactions against a real block evaluator #4436

Merged
merged 85 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
8f840dc
Add simulate endpoint to OpenAPI file
jdtzmn Jul 20, 2022
62f4b59
Basic simulation endpoint with failure message
jdtzmn Jul 25, 2022
505bc50
Return msgpack response instead of JSON
jdtzmn Jul 26, 2022
58846a3
Test Simulator class with basic pay transactions
jdtzmn Jul 27, 2022
e242bc4
Use genesis methods for block header creation
jdtzmn Jul 27, 2022
63805af
Test simple group transaction
jdtzmn Jul 27, 2022
5d93ceb
Trivial app create and call test
jdtzmn Jul 27, 2022
2c8c912
Remove budget error gatekeeping for now
jdtzmn Jul 27, 2022
b9f96ee
Add invalid signature check
jdtzmn Jul 28, 2022
e52d1bf
Lowercase simulate test methods to make them private
jdtzmn Jul 28, 2022
a9f4d1a
Add balance change test
jdtzmn Jul 28, 2022
8a54d2e
Merge branch 'feature/simulate-endpoint' into psuedo-eval-endpoint
jdtzmn Jul 29, 2022
301a366
Implement newly included ledger methods introduced in the merge
jdtzmn Jul 29, 2022
06d0063
Fix unkeyed struct fields
jdtzmn Jul 29, 2022
0631333
Fix golint errors
jdtzmn Jul 29, 2022
7f0b564
Spec file changes
jdtzmn Aug 1, 2022
6e5c9ce
Use new flag for configuring simulation endpoint visibility
jdtzmn Aug 2, 2022
64567aa
Check node status separately from transaction decoding
jdtzmn Aug 2, 2022
fc76cb2
Write interface annotations
jdtzmn Aug 2, 2022
760bbfb
Add docstring to MakeLedgerForRound
jdtzmn Aug 2, 2022
cc6e605
Use error type to fix fragile signature error check
jdtzmn Aug 2, 2022
c51926f
Fix signature check and add invalid signature test
jdtzmn Aug 2, 2022
deb330f
Test reject app call
jdtzmn Aug 2, 2022
19cdb73
Disable transaction simulator by default
jdtzmn Aug 4, 2022
462a9dd
Fix API spec descriptions
jdtzmn Aug 5, 2022
b2c4f51
Improve `decodeTxGroup`
jdtzmn Aug 4, 2022
6ec12f1
Clean up simulator ledger
jdtzmn Aug 5, 2022
b5473ae
Add invalid transaction group test
jdtzmn Aug 5, 2022
307709d
Make `SignatureError` a struct
jdtzmn Aug 5, 2022
7995700
Cleanup simulator tests
jdtzmn Aug 5, 2022
02d0947
Remove “contact us” language and cut helper function used in only one…
jdtzmn Aug 5, 2022
a3e0f59
Handle returned error from `attachGroupID`
jdtzmn Aug 5, 2022
dad0197
Cleaner implementation by going through `Node` instead of `LedgerForAPI`
jdtzmn Aug 8, 2022
ac72228
Rename `makeSimulateEnv` to `prepareSimulatorTest`
jdtzmn Aug 8, 2022
50304a3
Use `MissingSignatures` boolean instead of `SignatureFailureMessage`
jdtzmn Aug 8, 2022
33dda59
Implement renamed `MissingSignatures`
jdtzmn Aug 8, 2022
f1c0b05
Improve Simulator `check` to catch badly formed transactions when sig…
jdtzmn Aug 8, 2022
f90c19a
Document allowing unsigned transactions
jdtzmn Aug 8, 2022
394f7e7
Correctly catch CompactCert special case
jdtzmn Aug 9, 2022
be38467
Simplify TxnIsMissingSig logic
jdtzmn Aug 9, 2022
970d9f4
Fix linter errors
jdtzmn Aug 9, 2022
595ca6b
Refactor Simulator to be more general
jdtzmn Aug 9, 2022
5f45dfe
Deprecate no longer needed `SimulationResult`
jdtzmn Aug 9, 2022
7897a2e
Fix shortened property names in API spec
jdtzmn Aug 9, 2022
051cbef
Test pooled fees
jdtzmn Aug 9, 2022
65cba5c
Support verifying transaction groups with missing signatures
jdtzmn Aug 9, 2022
b78e899
Test non-overriden `data.Ledger` methods used during evaluation have …
jdtzmn Aug 9, 2022
cb381d8
Fix test name typo
jdtzmn Aug 10, 2022
2d92ad4
Return error in `LookupLatest` override since panics within API handl…
jdtzmn Aug 10, 2022
2f189d2
Add missing `PartitionTest()`
jdtzmn Aug 11, 2022
5bf32e7
Improve test step description
jdtzmn Aug 12, 2022
c7996d3
Favor explicit returns within `txnGroupBatchVerify`
jdtzmn Aug 18, 2022
08f8e5e
Remove unused `ScopedSimulatorError` artifact
jdtzmn Aug 18, 2022
6e448a8
Remove extra space (#4435)
jdtzmn Aug 19, 2022
139672a
Undo changes to txn verification code, use proxy signer instead
jasonpaulos Aug 23, 2022
6ad7387
More simulator tests
jasonpaulos Aug 23, 2022
47e83dc
Merge branch 'master' into psuedo-eval-endpoint
jasonpaulos Aug 23, 2022
ba5d43e
Fix merge issues
jasonpaulos Aug 23, 2022
82f31c8
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Aug 23, 2022
d3e4253
Merge branch 'feature/simulate-endpoint' into psuedo-eval-endpoint
jasonpaulos Aug 23, 2022
bf3907b
Revert unintended change
jasonpaulos Aug 23, 2022
1e518be
Not sure what happened, but fix routes again
jasonpaulos Aug 23, 2022
e7ce7fc
Add comments about future LogicSig support
jasonpaulos Aug 24, 2022
042704a
Make a copy of the txgroup when checking sigs
jasonpaulos Aug 29, 2022
ca59421
CR feedback
jasonpaulos Aug 29, 2022
a0a0550
Merge pull request #4322 from jdtzmn/psuedo-eval-endpoint
jasonpaulos Aug 29, 2022
b99b80b
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Oct 31, 2022
ad5f515
Fix generate config files
jasonpaulos Oct 31, 2022
533c239
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Nov 1, 2022
807b384
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 8, 2022
3f4e74e
Clarify group transactions are also acceptable
jasonpaulos Dec 8, 2022
4a74a24
Try to appease the new parallel linter
jasonpaulos Dec 8, 2022
2f083e8
Classify simulation endpoint as experimental
jasonpaulos Dec 9, 2022
3c5bc99
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 9, 2022
70ddd43
Rename EnableTransactionSimulator to EnableExperimentalAPI
jasonpaulos Dec 12, 2022
6de00a4
Update config.json.example
jasonpaulos Dec 12, 2022
f153f4a
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 14, 2022
d1f0d0e
Make experimental routes public
jasonpaulos Dec 14, 2022
845425b
Add to API docs
jasonpaulos Dec 14, 2022
075e288
Missing change to README
jasonpaulos Dec 14, 2022
84c5dff
Add experimental warning to swagger file
jasonpaulos Dec 15, 2022
446d158
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 15, 2022
aa3565a
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 17, 2022
069a0a0
Update API readme
jasonpaulos Dec 19, 2022
6ad3ffc
Merge branch 'master' into feature/simulate-endpoint
jasonpaulos Dec 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/localTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,10 @@ type Local struct {
// 0x01 (txFilterRawMsg) - check for raw tx message duplicates
// 0x02 (txFilterCanonical) - check for canonical tx group duplicates
TxIncomingFilteringFlags uint32 `version[26]:"1"`

// EnableExperimentalAPI enables experimental API endpoint. Note that these endpoints have no
// guarantees in terms of functionality or future support.
EnableExperimentalAPI bool `version[26]:"false"`
}

// DNSBootstrapArray returns an array of one or more DNS Bootstrap identifiers
Expand Down
1 change: 1 addition & 0 deletions config/local_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ var defaultLocal = Local{
EnableBlockServiceFallbackToArchiver: true,
EnableCatchupFromArchiveServers: false,
EnableDeveloperAPI: false,
EnableExperimentalAPI: false,
EnableGossipBlockService: true,
EnableIncomingMessageFilter: false,
EnableLedgerService: false,
Expand Down
2 changes: 1 addition & 1 deletion crypto/merklesignature/committablePublicKeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type (
keyLifetime uint64
}

// CommittablePublicKey is used to create a binary representation of public keys in the merkle
// CommittablePublicKey is used to create a binary representation of public keys in the merkle
// signature scheme.
CommittablePublicKey struct {
VerifyingKey crypto.FalconVerifier
Expand Down
5 changes: 4 additions & 1 deletion daemon/algod/api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ GOPATH := $(shell go env GOPATH)
GOPATH1 := $(firstword $(subst :, ,$(GOPATH)))

# `make all` or just `make` should be appropriate for dev work
all: server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go server/v2/generated/data/routes.go
all: server/v2/generated/model/types.go server/v2/generated/nonparticipating/public/routes.go server/v2/generated/nonparticipating/private/routes.go server/v2/generated/participating/public/routes.go server/v2/generated/participating/private/routes.go server/v2/generated/data/routes.go server/v2/generated/experimental/routes.go

# `make generate` should be able to replace old `generate.sh` script and be appropriate for build system use
generate: oapi-codegen all
Expand All @@ -23,6 +23,9 @@ server/v2/generated/participating/private/routes.go: algod.oas3.yml
server/v2/generated/data/routes.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/data/data_routes.yml algod.oas3.yml

server/v2/generated/experimental/routes.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/experimental/experimental_routes.yml algod.oas3.yml

server/v2/generated/model/types.go: algod.oas3.yml
$(GOPATH1)/bin/oapi-codegen -config ./server/v2/generated/model/model_types.yml algod.oas3.yml

Expand Down
10 changes: 6 additions & 4 deletions daemon/algod/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ Each API in `algod.oas2.json`, except for some pre-existing `common` APIs, shoul
1. Either `public` or `private`. This controls the type of authentication used by the API--the `public` APIs use the
`algod.token` token, while the `private` APIs use the admin token, found in `algod.admin.token` within the algod data
directory.
2. The type, or group, of API. This is currently `participating`, `nonparticipating`, or `data`, but may expand in the
future to encompass different sets of APIs such as `experimental` APIs. Additional APIs should be added to one of the
existing sets of tags based on its use case--unless you intend to create a new group in which case you will need to
additionally ensure your new APIs are registered.
2. The type, or group, of API. This is currently `participating`, `nonparticipating`, `data`, or `experimental`, but
may expand in the future to encompass different sets of APIs. Additional APIs should be added to one of the existing
sets of tags based on its use case--unless you intend to create a new group in which case you will need to additionally
ensure your new APIs are registered.

For backwards compatibility, the default set of APIs registered will always be `participating` and `nonparticipating`
APIs.
Expand All @@ -38,6 +38,8 @@ participation keys, the agreement service, etc.
* A special set of APIs which require manipulating the node state in order to provide additional data about the node state
at some predefined granularity. For example, SetSyncRound and GetLedgerStateDelta used together control and expose StateDelta objects
containing per-round ledger differences that get compacted when actually written to the ledger DB.
* `experimental`
* APIs which are still in development and not ready to be generally released.

## What codegen tool is used?

Expand Down
88 changes: 87 additions & 1 deletion daemon/algod/api/algod.oas2.json
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,7 @@
"schemes": [
"http"
],
"summary": "Broadcasts a raw transaction to the network.",
"summary": "Broadcasts a raw transaction or transaction group to the network.",
"operationId": "RawTransaction",
"parameters": [
{
Expand Down Expand Up @@ -1205,6 +1205,69 @@
}
}
},
"/v2/transactions/simulate": {
"post": {
"tags": [
"public",
"experimental"
],
"consumes": [
"application/x-binary"
],
"produces": [
"application/msgpack"
],
"schemes": [
"http"
],
"summary": "Simulates a raw transaction or transaction group as it would be evaluated on the network. WARNING: This endpoint is experimental and under active development. There are no guarantees in terms of functionality or future support.",
"operationId": "SimulateTransaction",
"parameters": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we add a SimulationOptions struct now, even if it's nearly empty? We'll eventually need a place for parameters like "run me in 'access any resource mode`" or "Run me against the latest block OR run me against the end of the current pending queue".

We'll also need a place for incoming state, so this becomes a suitable replacement for dry-run, but I suspect that ought to be a third parameter, to keep "options" separate from "state".

I am also ok with not doing this now.

Copy link
Contributor

@jasonpaulos jasonpaulos Dec 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a problem if we want to have additional arguments in the request body (and if the goal is to specify initial state, that seems like it would need to be in the body, not on the URL).

Right now we mimic the raw transaction submission endpoint and treat the entire body as sign transaction bytes. There's no place for other arguments to be encoded.

We probably need to think of a way to also accept other arguments without differentiating too much from the raw transaction endpoint.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear I don't think a change is necessary at the moment, but we should think about this and try to address it before we make the endpoint generally available

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we need some sort of "envelope" to contain the transaction(s) and metadata. I find myself wanting this in the protocol itself often as well.

{
"description": "The byte encoded transaction to simulate",
"name": "rawtxn",
"in": "body",
"required": true,
"schema": {
"type": "string",
"format": "binary"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/SimulationResponse"
},
"400": {
"description": "Bad Request - Malformed Algorand transaction",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
},
"401": {
"description": "Invalid API Token",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
},
"503": {
"description": "Service Temporarily Unavailable",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
},
"default": {
"description": "Unknown Error"
}
}
}
},
"/v2/transactions/params": {
"get": {
"tags": [
Expand Down Expand Up @@ -4128,6 +4191,29 @@
}
}
},
"SimulationResponse": {
"description": "Result of a transaction group simulation.",
"tags": [
"experimental"
],
"schema": {
"type": "object",
"required": [
"failure-message",
"missing-signatures"
],
"properties": {
"failure-message": {
"description": "\\[fm\\] Failure message, if the transaction would have failed during a live broadcast.",
"type": "string"
},
"missing-signatures": {
"description": "\\[ms\\] Whether any transactions would have failed during a live broadcast because they were missing signatures.",
"type": "boolean"
}
Comment on lines +4206 to +4213
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a placeholder for the actual information that will eventually be returned. It's intentionally minimal for the time being, and unless there's a serious concern, I'd rather leave this as is and focus on enriching this response in later PRs

}
}
},
"SupplyResponse": {
"description": "Supply represents the current supply of MicroAlgos in the system.",
"schema": {
Expand Down
119 changes: 118 additions & 1 deletion daemon/algod/api/algod.oas3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,30 @@
},
"description": "Transaction ID of the submission."
},
"SimulationResponse": {
"content": {
"application/json": {
"schema": {
"properties": {
"failure-message": {
"description": "\\[fm\\] Failure message, if the transaction would have failed during a live broadcast.",
"type": "string"
},
"missing-signatures": {
"description": "\\[ms\\] Whether any transactions would have failed during a live broadcast because they were missing signatures.",
"type": "boolean"
}
},
"required": [
"failure-message",
"missing-signatures"
],
"type": "object"
}
}
},
"description": "Result of a transaction group simulation."
},
"StateProofResponse": {
"content": {
"application/json": {
Expand Down Expand Up @@ -5346,7 +5370,7 @@
"description": "Unknown Error"
}
},
"summary": "Broadcasts a raw transaction to the network.",
"summary": "Broadcasts a raw transaction or transaction group to the network.",
"tags": [
"public",
"participating"
Expand Down Expand Up @@ -5687,6 +5711,99 @@
]
}
},
"/v2/transactions/simulate": {
"post": {
"operationId": "SimulateTransaction",
"requestBody": {
"content": {
"application/x-binary": {
"schema": {
"format": "binary",
"type": "string"
}
}
},
"description": "The byte encoded transaction to simulate",
"required": true
},
"responses": {
"200": {
"content": {
"application/msgpack": {
"schema": {
"properties": {
"failure-message": {
"description": "\\[fm\\] Failure message, if the transaction would have failed during a live broadcast.",
"type": "string"
},
"missing-signatures": {
"description": "\\[ms\\] Whether any transactions would have failed during a live broadcast because they were missing signatures.",
"type": "boolean"
}
},
"required": [
"failure-message",
"missing-signatures"
],
"type": "object"
}
}
},
"description": "Result of a transaction group simulation."
},
"400": {
"content": {
"application/msgpack": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Bad Request - Malformed Algorand transaction"
},
"401": {
"content": {
"application/msgpack": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Invalid API Token"
},
"500": {
"content": {
"application/msgpack": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Internal Error"
},
"503": {
"content": {
"application/msgpack": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Service Temporarily Unavailable"
},
"default": {
"content": {},
"description": "Unknown Error"
}
},
"summary": "Simulates a raw transaction or transaction group as it would be evaluated on the network. WARNING: This endpoint is experimental and under active development. There are no guarantees in terms of functionality or future support.",
"tags": [
"public",
"experimental"
],
"x-codegen-request-body-name": "rawtxn"
}
},
"/versions": {
"get": {
"description": "Retrieves the supported API versions, binary build versions, and genesis information.",
Expand Down
5 changes: 5 additions & 0 deletions daemon/algod/api/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/algorand/go-algorand/daemon/algod/api/server/lib/middlewares"
"github.com/algorand/go-algorand/daemon/algod/api/server/v1/routes"
v2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2"
"github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/experimental"
npprivate "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/nonparticipating/private"
nppublic "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/nonparticipating/public"
pprivate "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/participating/private"
Expand Down Expand Up @@ -112,6 +113,10 @@ func NewRouter(logger logging.Logger, node *node.AlgorandFullNode, shutdown <-ch
ppublic.RegisterHandlers(e, &v2Handler, apiAuthenticator)
pprivate.RegisterHandlers(e, &v2Handler, adminAuthenticator)

if node.Config().EnableExperimentalAPI {
experimental.RegisterHandlers(e, &v2Handler, apiAuthenticator)
}

return e
}

Expand Down
1 change: 1 addition & 0 deletions daemon/algod/api/server/v2/generated/data/data_routes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ output-options:
- private
- participating
- nonparticipating
- experimental
type-mappings:
integer: uint64
skip-prune: true
Expand Down
Loading