From 659fba7a323ad95ea444a6ed6a689850ea907137 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 25 Jun 2020 21:45:08 -0700 Subject: [PATCH 01/18] Add address derivation --- api.yaml | 64 ++++++++++++++++++++++++++++++++++++++++++- models/Curve.yaml | 20 ++++++++++++++ models/PublicKey.yaml | 31 +++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 models/Curve.yaml create mode 100644 models/PublicKey.yaml diff --git a/api.yaml b/api.yaml index f235b2d..23b8990 100644 --- a/api.yaml +++ b/api.yaml @@ -14,7 +14,7 @@ openapi: 3.0.2 info: - version: 1.3.1 + version: 1.4.0 title: Rosetta description: | A Standard for Blockchain Interaction @@ -288,6 +288,36 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/derive_address: + post: + summary: Derive an Address + description: | + DeriveAddress returns the network-specific address associated with a public key. + + Blockchains that require an on-chain action to create an + account should not implement this method. + operationId: constructionDeriveAddress + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionDeriveAddressRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionDeriveAddressResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/metadata: post: summary: Get Transaction Construction Metadata @@ -404,6 +434,8 @@ components: $ref: 'models/OperationStatus.yaml' Timestamp: $ref: 'models/Timestamp.yaml' + PublicKey: + $ref: 'models/PublicKey.yaml' # Request/Responses AccountBalanceRequest: @@ -662,6 +694,36 @@ components: example: account_sequence: 23 recent_block_hash: "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5" + ConstructionDeriveAddressRequest: + description: | + ConstructionDeriveAddressRequest is the input to the Address method. + Network is provided in the request because some blockchains + have different address formats for different networks. + Metadata is provided in the request because some blockchains + allow for multiple address types (i.e. different address + for validators vs normal accounts). + type: object + required: + - network_identifier + - public_key + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + public_key: + $ref: '#/components/schemas/PublicKey' + metadata: + type: object + ConstructionDeriveAddressResponse: + description: | + ConstructionDeriveAddressResponse is the output of the Address method. + type: object + required: + - address + properties: + address: + type: string + metadata: + type: object ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. diff --git a/models/Curve.yaml b/models/Curve.yaml new file mode 100644 index 0000000..7d70c37 --- /dev/null +++ b/models/Curve.yaml @@ -0,0 +1,20 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + Curve is the type of cryptographic curve associated with a PublicKey. +type: string +enum: + - secp256k1 + - edwards25519 diff --git a/models/PublicKey.yaml b/models/PublicKey.yaml new file mode 100644 index 0000000..adb7939 --- /dev/null +++ b/models/PublicKey.yaml @@ -0,0 +1,31 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + PublicKey contains a public key byte array + for a particular CurveType encoded in hex. + + Note that there is no PrivateKey struct as this + is NEVER the concern of an implementation. +type: object +required: + - hex_bytes + - curve +properties: + hex_bytes: + type: string + description: | + hex-encoded public key + curve: + $ref: "Curve.yaml" From b551e36c9ffd4b366b6b786da25c32528a69c892 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 07:55:01 -0700 Subject: [PATCH 02/18] prepare_metadata functions --- api.yaml | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/api.yaml b/api.yaml index 23b8990..cb80f97 100644 --- a/api.yaml +++ b/api.yaml @@ -318,6 +318,38 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/prepare_metadata: + post: + summary: Prepare a Request to Fetch Metadata + description: | + PrepareMetadata is called prior to ConstructTransaction to allow + a Rosetta API implementation to construct a request for any metadata + that is needed for transaction construction given (i.e. account nonce). + + The request returned from this method is sent directly to the endpoint + `/construction/metadata`. + operationId: constructionPrepareMetadata + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionPrepareMetadataRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionPrepareMetadataResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/metadata: post: summary: Get Transaction Construction Metadata @@ -722,8 +754,38 @@ components: properties: address: type: string + description: | + Address in network-specific format. metadata: type: object + ConstructionPrepareMetadataRequest: + description: | + ConstructionPrepareMetadataRequest is the input to the RequiredMetadata + method. + type: object + required: + - network_identifier + - operations + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + operations: + type: array + items: + $ref: '#/components/schemas/Operation' + metadata: + type: object + ConstructionPrepareMetadataResponse: + description: | + ConstructionPrepareMetadataResponse contains the request that will + be sent directly to `/construction/metadata`. + + If it is not necessary to make a request to `/construction/metadata`, + request should be null. + type: object + properties: + request: + type: object ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. From 3084dba17d19d18e978b0821b6c183b0d603ba44 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 08:12:53 -0700 Subject: [PATCH 03/18] Add create_payloads --- api.yaml | 65 ++++++++++++++++++++++++++++++++++++++ models/Signature.yaml | 21 ++++++++++++ models/SigningPayload.yaml | 33 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 models/Signature.yaml create mode 100644 models/SigningPayload.yaml diff --git a/api.yaml b/api.yaml index cb80f97..31d8db4 100644 --- a/api.yaml +++ b/api.yaml @@ -391,6 +391,36 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/create_payloads: + post: + summary: Create Signing Payloads + description: | + ConstructTransaction is called with an array of operations and the response + from `/construction/metadata` (if applicable). It returns an + unsigned transaction blob and a collection of payloads that must be signed + by particular addresses using a certain SignatureType. + operationId: constructionCreatePayloads + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionCreatePayloadsRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionCreatePayloadsResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/submit: post: summary: Submit a Signed Transaction @@ -468,6 +498,8 @@ components: $ref: 'models/Timestamp.yaml' PublicKey: $ref: 'models/PublicKey.yaml' + SigningPayload: + $ref: 'models/SigningPayload.yaml' # Request/Responses AccountBalanceRequest: @@ -786,6 +818,39 @@ components: properties: request: type: object + ConstructionCreatePayloadsRequest: + description: | + ConstructTransactionRequest is the input to + ConstructTransaction. It contains the network, + a slice of operations, and arbitrary metadata + that was returned by the call to `/construction/metadata`. + type: object + required: + - network_identifier + - operations + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + operations: + type: array + items: + $ref: '#/components/schemas/Operation' + metadata: + type: object + ConstructionCreatePayloadsResponse: + description: | + ConstructTransactionResponse is the output of ConstructTransaction. + type: object + required: + - unsigned_transaction + - payloads + properties: + unsigned_transaction: + type: string + payloads: + type: array + items: + $ref: '#/components/schemas/SigningPayload' ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. diff --git a/models/Signature.yaml b/models/Signature.yaml new file mode 100644 index 0000000..4d72b50 --- /dev/null +++ b/models/Signature.yaml @@ -0,0 +1,21 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + SignatureType is the type of a cryptographic signature. +type: string +enum: + - ecdsa + - ecdsa_recovery + - ed25519 diff --git a/models/SigningPayload.yaml b/models/SigningPayload.yaml new file mode 100644 index 0000000..9252ba2 --- /dev/null +++ b/models/SigningPayload.yaml @@ -0,0 +1,33 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + SigningPayload is signed by the client with the keypair associated + with an address using the specified SignatureType. + + [TODO] explain that signature_type is provided optionally + if there is a restriction. Otherwise, leave blank for default + or if multiple accepted (does not mean any signature type can + be used). +type: object +required: + - address + - hex_bytes +properties: + address: + type: string + hex_bytes: + type: string + signature_type: + $ref: "Signature.yaml" From 5b9fc9d702df4a1850ce1312d797ee1d0525f438 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 08:27:10 -0700 Subject: [PATCH 04/18] Combine signatures support --- api.yaml | 65 +++++++++++++++++++++++++++ models/{Curve.yaml => CurveType.yaml} | 2 +- models/PublicKey.yaml | 6 +-- models/Signature.yaml | 24 +++++++--- models/SignatureType.yaml | 21 +++++++++ models/SigningPayload.yaml | 2 +- 6 files changed, 109 insertions(+), 11 deletions(-) rename models/{Curve.yaml => CurveType.yaml} (89%) create mode 100644 models/SignatureType.yaml diff --git a/api.yaml b/api.yaml index 31d8db4..7947b72 100644 --- a/api.yaml +++ b/api.yaml @@ -421,6 +421,37 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/combine_signatures: + post: + summary: Create Transaction from Signatures + description: | + CombineSignatures creates a network-specific transaction from an unsigned + transaction and a collection of payload signatures. + + The signed transaction returned from this method is sent directly to the + endpoint `/construction/submit`. + operationId: constructionCombineSignatures + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionCombineSignaturesRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionCombineSignaturesResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/submit: post: summary: Submit a Signed Transaction @@ -498,8 +529,14 @@ components: $ref: 'models/Timestamp.yaml' PublicKey: $ref: 'models/PublicKey.yaml' + CurveType: + $ref: 'models/CurveType.yaml' SigningPayload: $ref: 'models/SigningPayload.yaml' + Signature: + $ref: 'models/Signature.yaml' + SignatureType: + $ref: 'models/SignatureType.yaml' # Request/Responses AccountBalanceRequest: @@ -851,6 +888,34 @@ components: type: array items: $ref: '#/components/schemas/SigningPayload' + ConstructionCombineSignaturesRequest: + description: | + CombineSignaturesRequest is the input to CombineSignatures. + type: object + required: + - network_identifier + - unsigned transaction + - signatures + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + unsigned_transaction: + type: string + signatures: + type: array + items: + $ref: '#/components/schemas/Signature' + ConstructionCombineSignaturesResponse: + description: | + CombineSignaturesResponse is the output of CombineSignatures. + The NetworkPayload will be sent directly to the Node API + `construction/submit` endpoint. + type: object + required: + - network_payload + properties: + network_payload: + type: string ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. diff --git a/models/Curve.yaml b/models/CurveType.yaml similarity index 89% rename from models/Curve.yaml rename to models/CurveType.yaml index 7d70c37..565be6c 100644 --- a/models/Curve.yaml +++ b/models/CurveType.yaml @@ -13,7 +13,7 @@ # limitations under the License. description: | - Curve is the type of cryptographic curve associated with a PublicKey. + CurveType is the type of cryptographic curve associated with a PublicKey. type: string enum: - secp256k1 diff --git a/models/PublicKey.yaml b/models/PublicKey.yaml index adb7939..c1d5888 100644 --- a/models/PublicKey.yaml +++ b/models/PublicKey.yaml @@ -21,11 +21,11 @@ description: | type: object required: - hex_bytes - - curve + - curve_type properties: hex_bytes: type: string description: | hex-encoded public key - curve: - $ref: "Curve.yaml" + curve_type: + $ref: "CurveType.yaml" diff --git a/models/Signature.yaml b/models/Signature.yaml index 4d72b50..0942010 100644 --- a/models/Signature.yaml +++ b/models/Signature.yaml @@ -13,9 +13,21 @@ # limitations under the License. description: | - SignatureType is the type of a cryptographic signature. -type: string -enum: - - ecdsa - - ecdsa_recovery - - ed25519 + Signature contains the payload that was signed, the public keys of the + keypairs used to produce the signature, the signature (encoded in hex), + and the SignatureType. +type: object +required: + - signing_payload + - public_key + - signature_type + - hex_bytes +properties: + signing_payload: + $ref: "SigningPayload.yaml" + public_key: + $ref: "PublicKey.yaml" + signature_type: + $ref: "SignatureType.yaml" + hex_bytes: + type: string diff --git a/models/SignatureType.yaml b/models/SignatureType.yaml new file mode 100644 index 0000000..4d72b50 --- /dev/null +++ b/models/SignatureType.yaml @@ -0,0 +1,21 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + SignatureType is the type of a cryptographic signature. +type: string +enum: + - ecdsa + - ecdsa_recovery + - ed25519 diff --git a/models/SigningPayload.yaml b/models/SigningPayload.yaml index 9252ba2..429d14e 100644 --- a/models/SigningPayload.yaml +++ b/models/SigningPayload.yaml @@ -30,4 +30,4 @@ properties: hex_bytes: type: string signature_type: - $ref: "Signature.yaml" + $ref: "SignatureType.yaml" From 0a9b8ec8c215fed30d683ccffff6334334eb145f Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 08:38:59 -0700 Subject: [PATCH 05/18] Add support for parse --- api.yaml | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/api.yaml b/api.yaml index 7947b72..626d455 100644 --- a/api.yaml +++ b/api.yaml @@ -452,6 +452,36 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/parse: + post: + summary: Parse Transaction + description: | + ParseTransaction is called on both unsigned and signed transactions to + understand the intent of the formulated transaction. This is run as a + sanity check before signing (after ConstructTransaction) and before + broadcast (after CombineSignatures). + operationId: constructionParse + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionParseRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionParseResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/submit: post: summary: Submit a Signed Transaction @@ -894,7 +924,7 @@ components: type: object required: - network_identifier - - unsigned transaction + - unsigned_transaction - signatures properties: network_identifier: @@ -916,6 +946,42 @@ components: properties: network_payload: type: string + ConstructionParseRequest: + description: | + ParseTransactionRequest is the input to ParseTransaction. It allows + the client to parse either an unsigned or signed transaction. + type: object + required: + - network_identifier + - signed + - transaction + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + signed: + type: bool + transaction: + type: string + ConstructionParseResponse: + description: | + ParseTransactionResponse returns an array of operations that occur in + a transaction blob. This should match the array of operations provided + to ConstructTransactionRequest.Operations. + type: object + required: + - operations + - signers + properties: + operations: + type: array + items: + $ref: '#/components/schemas/Operation' + signers: + type: array + items: + type: string + metadata: + type: object ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. From f77013509c63ae4e91b4ce148be23018e6442540 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 08:48:30 -0700 Subject: [PATCH 06/18] Add support for transaction hash --- api.yaml | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/api.yaml b/api.yaml index 626d455..9ec5ac1 100644 --- a/api.yaml +++ b/api.yaml @@ -482,6 +482,34 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /construction/hash: + post: + summary: Get the Hash of a Signed Transaction + description: | + TransactionHash returns the network-specific transaction hash for + a signed transaction. + operationId: constructionHash + tags: + - Construction + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionHashRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/ConstructionHashResponse' + default: + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /construction/submit: post: summary: Submit a Signed Transaction @@ -982,6 +1010,27 @@ components: type: string metadata: type: object + ConstructionHashRequest: + description: | + TransactionHashRequest is the input of TransactionHash. + type: object + required: + - network_identifier + - signed_transaction + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + signed_transaction: + type: string + ConstructionHashResponse: + description: | + TransactionHashResponse is the output of TransactionHash. + type: object + required: + - transaction_hash + properties: + transaction_hash: + type: string ConstructionSubmitRequest: description: | The transaction submission request includes a signed transaction. From bb04f7714ca05afd463db50a469089bd745b3f4d Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 08:57:54 -0700 Subject: [PATCH 07/18] nits --- api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.yaml b/api.yaml index 9ec5ac1..f324ad3 100644 --- a/api.yaml +++ b/api.yaml @@ -17,7 +17,7 @@ info: version: 1.4.0 title: Rosetta description: | - A Standard for Blockchain Interaction + Build Once. Integrate Your Blockchain Everywhere. license: name: Apache 2.0 url: "http://www.apache.org/licenses/LICENSE-2.0.html" From 684bc66af1fd91a831eaeecb0d915fe638494815 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 10:37:15 -0700 Subject: [PATCH 08/18] Update endpoints --- api.yaml | 74 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/api.yaml b/api.yaml index f324ad3..b102708 100644 --- a/api.yaml +++ b/api.yaml @@ -27,7 +27,7 @@ paths: summary: Get List of Available Networks description: | This endpoint returns a list of NetworkIdentifiers that the Rosetta - server can handle. + server supports. operationId: networkList tags: - Network @@ -288,15 +288,15 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /construction/derive_address: + /construction/derive: post: - summary: Derive an Address + summary: Derive an Address from a public key description: | - DeriveAddress returns the network-specific address associated with a public key. + Derive returns the network-specific address associated with a public key. Blockchains that require an on-chain action to create an account should not implement this method. - operationId: constructionDeriveAddress + operationId: constructionDerive tags: - Construction requestBody: @@ -304,31 +304,31 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConstructionDeriveAddressRequest' + $ref: '#/components/schemas/ConstructionDeriveRequest' responses: '200': description: Expected response to a valid request content: application/json: schema: - $ref: '#/components/schemas/ConstructionDeriveAddressResponse' + $ref: '#/components/schemas/ConstructionDeriveResponse' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' - /construction/prepare_metadata: + /construction/preprocess: post: summary: Prepare a Request to Fetch Metadata description: | - PrepareMetadata is called prior to ConstructTransaction to allow + Preprocess is called prior to ConstructTransaction to allow a Rosetta API implementation to construct a request for any metadata that is needed for transaction construction given (i.e. account nonce). The request returned from this method is sent directly to the endpoint `/construction/metadata`. - operationId: constructionPrepareMetadata + operationId: constructionPreprocess tags: - Construction requestBody: @@ -336,14 +336,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConstructionPrepareMetadataRequest' + $ref: '#/components/schemas/ConstructionPreprocessRequest' responses: '200': description: Expected response to a valid request content: application/json: schema: - $ref: '#/components/schemas/ConstructionPrepareMetadataResponse' + $ref: '#/components/schemas/ConstructionPreprocessResponse' default: description: unexpected error content: @@ -391,15 +391,15 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - /construction/create_payloads: + /construction/payloads: post: - summary: Create Signing Payloads + summary: Create Unsigned Transaction and Signing Payloads description: | ConstructTransaction is called with an array of operations and the response from `/construction/metadata` (if applicable). It returns an unsigned transaction blob and a collection of payloads that must be signed by particular addresses using a certain SignatureType. - operationId: constructionCreatePayloads + operationId: constructionPayloads tags: - Construction requestBody: @@ -407,30 +407,30 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConstructionCreatePayloadsRequest' + $ref: '#/components/schemas/ConstructionPayloadsRequest' responses: '200': description: Expected response to a valid request content: application/json: schema: - $ref: '#/components/schemas/ConstructionCreatePayloadsResponse' + $ref: '#/components/schemas/ConstructionPayloadsResponse' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' - /construction/combine_signatures: + /construction/combine: post: summary: Create Transaction from Signatures description: | - CombineSignatures creates a network-specific transaction from an unsigned + Combine creates a network-specific transaction from an unsigned transaction and a collection of payload signatures. The signed transaction returned from this method is sent directly to the endpoint `/construction/submit`. - operationId: constructionCombineSignatures + operationId: constructionCombine tags: - Construction requestBody: @@ -438,14 +438,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConstructionCombineSignaturesRequest' + $ref: '#/components/schemas/ConstructionCombineRequest' responses: '200': description: Expected response to a valid request content: application/json: schema: - $ref: '#/components/schemas/ConstructionCombineSignaturesResponse' + $ref: '#/components/schemas/ConstructionCombineResponse' default: description: unexpected error content: @@ -459,7 +459,7 @@ paths: ParseTransaction is called on both unsigned and signed transactions to understand the intent of the formulated transaction. This is run as a sanity check before signing (after ConstructTransaction) and before - broadcast (after CombineSignatures). + broadcast (after Combine). operationId: constructionParse tags: - Construction @@ -853,9 +853,9 @@ components: example: account_sequence: 23 recent_block_hash: "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5" - ConstructionDeriveAddressRequest: + ConstructionDeriveRequest: description: | - ConstructionDeriveAddressRequest is the input to the Address method. + ConstructionDeriveRequest is the input to the Address method. Network is provided in the request because some blockchains have different address formats for different networks. Metadata is provided in the request because some blockchains @@ -872,9 +872,9 @@ components: $ref: '#/components/schemas/PublicKey' metadata: type: object - ConstructionDeriveAddressResponse: + ConstructionDeriveResponse: description: | - ConstructionDeriveAddressResponse is the output of the Address method. + ConstructionDeriveResponse is the output of the Address method. type: object required: - address @@ -885,9 +885,9 @@ components: Address in network-specific format. metadata: type: object - ConstructionPrepareMetadataRequest: + ConstructionPreprocessRequest: description: | - ConstructionPrepareMetadataRequest is the input to the RequiredMetadata + ConstructionPreprocessRequest is the input to the RequiredMetadata method. type: object required: @@ -902,9 +902,9 @@ components: $ref: '#/components/schemas/Operation' metadata: type: object - ConstructionPrepareMetadataResponse: + ConstructionPreprocessResponse: description: | - ConstructionPrepareMetadataResponse contains the request that will + ConstructionPreprocessResponse contains the request that will be sent directly to `/construction/metadata`. If it is not necessary to make a request to `/construction/metadata`, @@ -913,7 +913,7 @@ components: properties: request: type: object - ConstructionCreatePayloadsRequest: + ConstructionPayloadsRequest: description: | ConstructTransactionRequest is the input to ConstructTransaction. It contains the network, @@ -932,7 +932,7 @@ components: $ref: '#/components/schemas/Operation' metadata: type: object - ConstructionCreatePayloadsResponse: + ConstructionPayloadsResponse: description: | ConstructTransactionResponse is the output of ConstructTransaction. type: object @@ -946,9 +946,9 @@ components: type: array items: $ref: '#/components/schemas/SigningPayload' - ConstructionCombineSignaturesRequest: + ConstructionCombineRequest: description: | - CombineSignaturesRequest is the input to CombineSignatures. + CombineRequest is the input to Combine. type: object required: - network_identifier @@ -963,9 +963,9 @@ components: type: array items: $ref: '#/components/schemas/Signature' - ConstructionCombineSignaturesResponse: + ConstructionCombineResponse: description: | - CombineSignaturesResponse is the output of CombineSignatures. + CombineResponse is the output of Combine. The NetworkPayload will be sent directly to the Node API `construction/submit` endpoint. type: object From 8ceeec457c7ca7faef3fbf7a39ecfdd682d9ebda Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 10:39:53 -0700 Subject: [PATCH 09/18] Add flows to README --- README.md | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2d7a16e..cfacafa 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,139 @@ Requests and responses can be crafted with auto-generated code using Before diving into the specifications and starting your implementation, we recommend taking a look at the Rosetta API Docs: * [Overview](https://www.rosetta-api.org/docs/welcome.html) -* [Node API](https://www.rosetta-api.org/docs/node_api_introduction.html) -* [Wallet API (coming soon!)](https://www.rosetta-api.org/docs/wallet_api_introduction.html) +* [Data API](https://www.rosetta-api.org/docs/node_api_introduction.html) +* [Construction API](https://www.rosetta-api.org/docs/wallet_api_introduction.html) If you have any questions, don't hesitate to reach out in our [community forum](https://community.rosetta-api.org). -## Writing a Node API Implementation -If you've made it this far, you are interested in developing a Rosetta Node API implementation +## Flows +### Data API +``` + Caller (i.e. Coinbase) + Data API Implementation + +------------------------------------------------------------------------------------+ + X | + X Get Supported Networks +---------------------------------> /network/list + X | + + X +-----------+--------------------------------------------------------+ + Get supported networks, X | v | + their supported options, X | Get Network Options +------------------------------------> /network/options + and their status X | | + X +-----------+ | + X v | + X Get Network Status +-------------------------------------> /network/status + X | + | + X | + X Get Block +----------------------------------------------> /block + X | + + +---------+X +-----------------------------------------------+ + | X v | +Ensure balance computed | X [Optional] Get Additional Block Transactions +-----------> /block/transaction +from block operations | X | +equals balance on node | | + | | + +-----------> Get account balance for each +---------------------------> /account/balance + account seen in a block | + | + | + X | + X Get Mempool Transactions +-------------------------------> /mempool + Monitor the mempool for X | + + broadcast transaction status X +-----------------------------------------------+ + and incoming deposits X v | + X Get a Specific Mempool Transaction +---------------------> /mempool/transaction + X | + + +``` + +### Construction API +#### Offline +``` + Caller (i.e. Coinbase) + Construction API Implementation + +-------------------------------------------------------------------------------------------+ + | + Derive Address +----------------------------> /construction/derive + from Public Key | + | + X | + X Create Metadata Request +---------------------> /construction/preprocess + X (array of operations) | + + Get metadata needed X | | + to construct transaction X +-----------------------------------------------+ + X v | + X Fetch Online Metadata +-----------------------> /construction/metadata (online) + X | + | + X | + X Construct Payloads to Sign +------------------> /construction/payloads + X (array of operations) | + + X | | + Create unsigned transaction X +------------------------------------------------+ + X v | + X Parse Unsigned Transaction +------------------> /construction/parse + X to Confirm Correctness | + X | + | + X | + X Sign Payload(s) +-----------------------------> /construction/combine + X (using caller's own detached signer) | + + X | | + Create signed transaction X +-----------------------------------------------+ + X v | + X Parse Signed Transaction +--------------------> /construction/parse + X to Confirm Correctness | + X | + | + X | + X Get hash of signed transaction +--------------> /construction/hash +Broadcast Signed Transaction X to monitor status | + X | + X Submit Transaction +--------------------------> /construction/submit + X | + + +``` + +#### Online +``` + Caller (i.e. Mobile Wallet) + Construction API Implementation + +-------------------------------------------------------------------------------------------+ + | + Derive Address +----------------------------> /construction/derive + from Public Key | + | X + | X Fetch metadata needed for + | X construction automatically + X | X + X Construct Payloads to Sign +------------------> /construction/payloads X /construction/preprocess + X (array of operations) | + X + + X | | X v + Create unsigned transaction X +------------------------------------------------+ X /construction/metadata + X v | X + X Parse Unsigned Transaction +------------------> /construction/parse + X to Confirm Correctness | + X | + | + X | + X Sign Payload(s) +-----------------------------> /construction/combine + X (using caller's own detached signer) | + + X | | + Create signed transaction X +-----------------------------------------------+ + X v | + X Parse Signed Transaction +--------------------> /construction/parse + X to Confirm Correctness | + X | + | + X | + X Get hash of signed transaction +--------------> /construction/hash +Broadcast Signed Transaction X to monitor status | + X | + X Submit Transaction +--------------------------> /construction/submit + X | + + +``` + +## Writing a Data API Implementation +If you've made it this far, you are interested in developing a Rosetta Data API implementation for a blockchain project you are working on. As mentioned in the Rosetta doumentation, there is [no restriction on what language you choose to use for your implementation](https://www.rosetta-api.org/docs/no_gatekeepers.html#no-required-languages) and [no repository](https://www.rosetta-api.org/docs/no_gatekeepers.html#no-master-repository) @@ -46,10 +172,10 @@ for integration (make sure your implementation meets the ["expectations" of any implementation](https://www.rosetta-api.org/docs/node_deployment.html)). ### Using Golang -If you are comfortable with Golang, the easiest way to write a Rosetta Node API implementation +If you are comfortable with Golang, the easiest way to write a Rosetta Data API implementation is to use [rosetta-sdk-go](https://github.com/coinbase/rosetta-sdk-go). This Golang project provides a [server package](https://github.com/coinbase/rosetta-sdk-go/tree/master/server) that -empowers a developer to write a full Rosetta Node API server by only implementing an interface. +empowers a developer to write a full Rosetta Data API server by only implementing an interface. This package automatically validates client requests and calls the functions you implement with pre-parsed requests (instead of in raw JSON). @@ -65,6 +191,9 @@ so that other developers can use it (see the note on [SDKs in more languages](#s [rosetta-sdk-go](https://github.com/coinbase/rosetta-sdk-go) for an example of how to generate code from this specification. +## Writing a Construction API Implementation +TODO + ## Validating Your Implementation To validate your implementation, you'll need to run the [rosetta-cli](https://github.com/coinbase/rosetta-cli). The `rosetta-cli` has a command called `check` that can be used to ensure your implementation @@ -88,7 +217,7 @@ for all block processing. ### Syncer The core of any integration is syncing blocks reliably. The [syncer](https://github.com/coinbase/rosetta-sdk-go/tree/master/syncer) -serially processes blocks from a Node API implementation (automatically handling re-orgs) with +serially processes blocks from a Data API implementation (automatically handling re-orgs) with user-defined handling logic and pluggable storage. After a block is processed, store it to a DB or send a push notification...it's up to you! From c202949993e4390d02607918389e1bab05d21066 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 11:02:46 -0700 Subject: [PATCH 10/18] Update README with more explanation and context --- README.md | 100 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index cfacafa..a0c8d74 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,20 @@ Requests and responses can be crafted with auto-generated code using [OpenAPI Generator](https://openapi-generator.tech), are human-readable (easy to debug and understand), and can be used in servers and browsers. -## Documentation -Before diving into the specifications and starting your implementation, we recommend taking a look at the Rosetta API Docs: +## Flow of Operations +Before diving into the specification and documentation, we recommend reviewing +the high-level diagrams below to gain some familiarity with the functionality +of the Rosetta APIs. -* [Overview](https://www.rosetta-api.org/docs/welcome.html) -* [Data API](https://www.rosetta-api.org/docs/node_api_introduction.html) -* [Construction API](https://www.rosetta-api.org/docs/wallet_api_introduction.html) +The Rosetta APIs are organized into two distinct categories, the Data API and +the Construction API. Simply put, the Data API is for retrieving data from +a blockchain network and the Construction API is for constructing and +submitting transactions to a blockchain network. -If you have any questions, don't hesitate to reach out in our [community forum](https://community.rosetta-api.org). +_The Data API was previously known as the Node API and the Construction API +was previously known as the Wallet API. Their names were changed to better +reflect their functionality._ -## Flows ### Data API ``` Caller (i.e. Coinbase) + Data API Implementation @@ -72,7 +76,13 @@ equals balance on node | ``` ### Construction API -#### Offline +If you have seen illustrations of the flow of transaction +construction in other blockchain SDKs, the following diagrams +may seem peculiar to you. Unlike traditional SDKs, Construction API +implementations are fully stateless, can perform construction +offline (when metadata like an account nonce is pre-fetched), +and never have access to private key material. + ``` Caller (i.e. Coinbase) + Construction API Implementation +-------------------------------------------------------------------------------------------+ @@ -118,7 +128,19 @@ Broadcast Signed Transaction X to monitor status | + ``` -#### Online +#### Simplified Flow using a Higher-Level Interface +Many developers may not have security constraints that dictate construction must +occur offline or that they use their own detached signer (making the previously +described flow much more cumbersome than other transaction construction and +signing SDKs). + +Fortunately, it is possible (and encouraged) to build higher-level interfaces +on top of these low-level endpoints to simplify development for integrators. +For example, an interface developer may wish to automatically fetch metdata +during their call to construct a transaction so users would not even +know there are multiple interactions occuring. One could also provide +a signing library with their higher-level interface so users do not need +to use a detached signer. Here is an example of a simplified flow: ``` Caller (i.e. Mobile Wallet) + Construction API Implementation +-------------------------------------------------------------------------------------------+ @@ -129,18 +151,13 @@ Broadcast Signed Transaction X to monitor status | | X Fetch metadata needed for | X construction automatically X | X - X Construct Payloads to Sign +------------------> /construction/payloads X /construction/preprocess - X (array of operations) | + X + - X | | X v - Create unsigned transaction X +------------------------------------------------+ X /construction/metadata - X v | X - X Parse Unsigned Transaction +------------------> /construction/parse - X to Confirm Correctness | - X | - | - X | + Create unsigned transaction X Construct Payloads to Sign +------------------> /construction/payloads X /construction/preprocess + X (array of operations) | X + + X | X v + | X /construction/metadata + X | X X Sign Payload(s) +-----------------------------> /construction/combine - X (using caller's own detached signer) | + + X (using rosetta-sdk-go keys package) | + X | | Create signed transaction X +-----------------------------------------------+ X v | @@ -157,6 +174,22 @@ Broadcast Signed Transaction X to monitor status | + ``` +Why go through all this trouble to build a higher-level interface on this +Construction API instead of just using existing SDKs, you may be wondering? +Any interface built on top of the Construction API could support the construction +of transactions on any blockchain that supports Rosetta with no modification. +You could, for example, build a [WalletLink](https://www.walletlink.org/) service +that worked with any blockchain. + +## Documentation +Now that you have some familiarity with the flow of operations, we recommend taking a look at the Rosetta API Docs: + +* [Overview](https://www.rosetta-api.org/docs/welcome.html) +* [Data API](https://www.rosetta-api.org/docs/node_api_introduction.html) +* [Construction API](https://www.rosetta-api.org/docs/wallet_api_introduction.html) + +If you have any questions, don't hesitate to reach out in our [community forum](https://community.rosetta-api.org). + ## Writing a Data API Implementation If you've made it this far, you are interested in developing a Rosetta Data API implementation for a blockchain project you are working on. As mentioned in the Rosetta doumentation, there @@ -192,7 +225,32 @@ so that other developers can use it (see the note on [SDKs in more languages](#s code from this specification. ## Writing a Construction API Implementation -TODO +In the near future, we will update this section with tips and helpful links for writing a +Construction API implementation. + +## Deployment +Although the Construction API is defined in the same interface as endpoints that +are "online" (i.e. fetching a block with `/block`), it must be possible to deploy your Data API +and Construction API separately. This does not mean implementations need to live +in separate repositories or even be defined in separate Dockerfiles. However, it must be possible +to start an "offline-only" version of your implementation that supports all Construction API +endpoints (other than `/construction/metadata` and `/construction/submit`). + +### Online Mode Endpoints +* `/network/*` +* `/block/*` +* `/account/*` +* `/mempool/*` +* `/construction/metadata` +* `/construction/submit` + +### Offline Mode Endpoints +* `/construction/derive` +* `/construction/preprocess` +* `/construction/payloads` +* `/construction/combine` +* `/construction/parse` +* `/construction/hash` ## Validating Your Implementation To validate your implementation, you'll need to run the [rosetta-cli](https://github.com/coinbase/rosetta-cli). From 60bb7f21a6a0006fc42f67f353a00b2b403eb83e Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 13:09:42 -0700 Subject: [PATCH 11/18] Update api.yaml --- api.yaml | 128 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 72 insertions(+), 56 deletions(-) diff --git a/api.yaml b/api.yaml index b102708..180ea99 100644 --- a/api.yaml +++ b/api.yaml @@ -290,7 +290,7 @@ paths: $ref: '#/components/schemas/Error' /construction/derive: post: - summary: Derive an Address from a public key + summary: Derive an Address from a PublicKey description: | Derive returns the network-specific address associated with a public key. @@ -320,14 +320,15 @@ paths: $ref: '#/components/schemas/Error' /construction/preprocess: post: - summary: Prepare a Request to Fetch Metadata + summary: Create a Request to Fetch Metadata description: | - Preprocess is called prior to ConstructTransaction to allow - a Rosetta API implementation to construct a request for any metadata - that is needed for transaction construction given (i.e. account nonce). + Preprocess is called prior to `/construction/payloads` to construct a + request for any metadata that is needed for transaction construction + given (i.e. account nonce). - The request returned from this method is sent directly to the endpoint - `/construction/metadata`. + The request returned from this method will be used by the caller (in a + different execution environment) to call the `/construction/metadata` + endpoint. operationId: constructionPreprocess tags: - Construction @@ -352,23 +353,18 @@ paths: $ref: '#/components/schemas/Error' /construction/metadata: post: - summary: Get Transaction Construction Metadata + summary: Get Metadata for Transaction Construction description: | Get any information required to construct a transaction for a specific network. Metadata returned here could be a recent hash to use, an - account sequence number, or even arbitrary chain state. It is up to the - client to correctly populate the options object with any - network-specific details to ensure the correct metadata is retrieved. + account sequence number, or even arbitrary chain state. The request + used when calling this endpoint is often created by calling + `/construction/preprocess` in an offline environment. It is important to clarify that this endpoint should not pre-construct - any transactions for the client (this should happen in the SDK). This - endpoint is left purposely unstructured because of the wide scope + any transactions for the client (this should happen in `/construction/payloads`). + This endpoint is left purposely unstructured because of the wide scope of metadata that could be required. - - In a future version of the spec, we plan to pass an array of Rosetta - Operations to specify which metadata should be received and to create - a transaction in an accompanying SDK. This will help to insulate the - client from chain-specific details that are currently required here. operationId: constructionMetadata tags: - Construction @@ -393,12 +389,12 @@ paths: $ref: '#/components/schemas/Error' /construction/payloads: post: - summary: Create Unsigned Transaction and Signing Payloads + summary: Generate an Unsigned Transaction and Signing Payloads description: | - ConstructTransaction is called with an array of operations and the response - from `/construction/metadata` (if applicable). It returns an - unsigned transaction blob and a collection of payloads that must be signed - by particular addresses using a certain SignatureType. + Payloads is called with an array of operations + and the response from `/construction/metadata`. It returns an + unsigned transaction blob and a collection of payloads that must + be signed by particular addresses using a certain SignatureType. operationId: constructionPayloads tags: - Construction @@ -423,13 +419,13 @@ paths: $ref: '#/components/schemas/Error' /construction/combine: post: - summary: Create Transaction from Signatures + summary: Create Network Transaction from Signatures description: | Combine creates a network-specific transaction from an unsigned - transaction and a collection of payload signatures. + transaction and an array of provided signatures. - The signed transaction returned from this method is sent directly to the - endpoint `/construction/submit`. + The signed transaction returned from this method will be sent to the + `/construction/submit` endpoint by the caller. operationId: constructionCombine tags: - Construction @@ -454,12 +450,13 @@ paths: $ref: '#/components/schemas/Error' /construction/parse: post: - summary: Parse Transaction + summary: Parse a Transaction description: | - ParseTransaction is called on both unsigned and signed transactions to - understand the intent of the formulated transaction. This is run as a - sanity check before signing (after ConstructTransaction) and before - broadcast (after Combine). + Parse is called on both unsigned and signed transactions to + understand the intent of the formulated transaction. + + This is run as a sanity check before signing (after `/construction/payloads`) + and before broadcast (after `/construction/combine`). operationId: constructionParse tags: - Construction @@ -841,9 +838,7 @@ components: ConstructionMetadataResponse: description: | The ConstructionMetadataResponse returns network-specific metadata - used for transaction construction. It is likely that the client will - not inspect this metadata before passing it to a client SDK that uses - it for construction. + used for transaction construction. type: object required: - metadata @@ -855,8 +850,8 @@ components: recent_block_hash: "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5" ConstructionDeriveRequest: description: | - ConstructionDeriveRequest is the input to the Address method. - Network is provided in the request because some blockchains + ConstructionDeriveRequest is passed to the `/construction/derive` + endpoint. Network is provided in the request because some blockchains have different address formats for different networks. Metadata is provided in the request because some blockchains allow for multiple address types (i.e. different address @@ -874,7 +869,8 @@ components: type: object ConstructionDeriveResponse: description: | - ConstructionDeriveResponse is the output of the Address method. + ConstructionDeriveResponse is returned by the `/construction/derive` + endpoint. type: object required: - address @@ -887,8 +883,9 @@ components: type: object ConstructionPreprocessRequest: description: | - ConstructionPreprocessRequest is the input to the RequiredMetadata - method. + ConstructionPreprocessRequest is passed to the `/construction/preprocess` + endpoint so that a Rosetta implementation can determine which + metadata it needs to request for construction. type: object required: - network_identifier @@ -908,15 +905,18 @@ components: be sent directly to `/construction/metadata`. If it is not necessary to make a request to `/construction/metadata`, - request should be null. + options should be null. type: object properties: - request: + options: type: object + description: | + The options that will be sent directly to `/construction/metadata` by + the caller. ConstructionPayloadsRequest: description: | - ConstructTransactionRequest is the input to - ConstructTransaction. It contains the network, + ConstructionPayloadsRequest is the request to + `/construction/payloads`. It contains the network, a slice of operations, and arbitrary metadata that was returned by the call to `/construction/metadata`. type: object @@ -934,7 +934,10 @@ components: type: object ConstructionPayloadsResponse: description: | - ConstructTransactionResponse is the output of ConstructTransaction. + ConstructionTransactionResponse is returned by `/construction/payloads`. It + contains an unsigned transaction blob (that is usually needed to construct + the a network transaction from a collection of signatures) and an + array of payloads that must be signed by the caller. type: object required: - unsigned_transaction @@ -948,7 +951,10 @@ components: $ref: '#/components/schemas/SigningPayload' ConstructionCombineRequest: description: | - CombineRequest is the input to Combine. + ConstructionCombineRequest is the input to the `/construction/combine` + endpoint. It contains the unsigned transaction blob returned by + `/construction/payloads` and all required signatures to create + a network transaction. type: object required: - network_identifier @@ -965,19 +971,20 @@ components: $ref: '#/components/schemas/Signature' ConstructionCombineResponse: description: | - CombineResponse is the output of Combine. - The NetworkPayload will be sent directly to the Node API + ConstructionCombineResponse is returned by `/construction/combine`. + The network payload will be sent directly to the `construction/submit` endpoint. type: object required: - - network_payload + - signed_transaction properties: - network_payload: + signed_transaction: type: string ConstructionParseRequest: description: | - ParseTransactionRequest is the input to ParseTransaction. It allows - the client to parse either an unsigned or signed transaction. + ConstructionParseRequest is the input to the `/construction/parse` + endpoint. It allows the caller to parse either an unsigned or + signed transaction. type: object required: - network_identifier @@ -988,13 +995,19 @@ components: $ref: '#/components/schemas/NetworkIdentifier' signed: type: bool + description: | + Signed is a boolean indicating whether the transaction is signed. transaction: type: string + description: | + This must be either the unsigned transaction blob returned by + `/construction/payloads` or the signed transaction blob + returned by `/construction/combine`. ConstructionParseResponse: description: | - ParseTransactionResponse returns an array of operations that occur in + ConstructionParseResponse contains an array of operations that occur in a transaction blob. This should match the array of operations provided - to ConstructTransactionRequest.Operations. + to `/construction/preprocess` and `/construction/payloads`. type: object required: - operations @@ -1005,6 +1018,9 @@ components: items: $ref: '#/components/schemas/Operation' signers: + description: | + All signers of a particular transaction. If the transaction + is unsigned, it should be empty. type: array items: type: string @@ -1012,7 +1028,7 @@ components: type: object ConstructionHashRequest: description: | - TransactionHashRequest is the input of TransactionHash. + ConstructionHashRequest is the input to the `/construction/hash` endpoint. type: object required: - network_identifier @@ -1024,7 +1040,7 @@ components: type: string ConstructionHashResponse: description: | - TransactionHashResponse is the output of TransactionHash. + ConstructionHashResponse is the output of the `/construction/hash` endpoint. type: object required: - transaction_hash From 51087f4ab11008b574e258389a609da8aec487a6 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 13:15:40 -0700 Subject: [PATCH 12/18] Add docs for new models --- models/PublicKey.yaml | 3 ++- models/Signature.yaml | 3 +++ models/SigningPayload.yaml | 10 ++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/models/PublicKey.yaml b/models/PublicKey.yaml index c1d5888..03a7ca6 100644 --- a/models/PublicKey.yaml +++ b/models/PublicKey.yaml @@ -26,6 +26,7 @@ properties: hex_bytes: type: string description: | - hex-encoded public key + Hex-encoded public key bytes in the format + specified by the CurveType. curve_type: $ref: "CurveType.yaml" diff --git a/models/Signature.yaml b/models/Signature.yaml index 0942010..9ccfec8 100644 --- a/models/Signature.yaml +++ b/models/Signature.yaml @@ -16,6 +16,9 @@ description: | Signature contains the payload that was signed, the public keys of the keypairs used to produce the signature, the signature (encoded in hex), and the SignatureType. + + PublicKey is often times not known during construction of the signing payloads + but may be needed to combine signatures properly. type: object required: - signing_payload diff --git a/models/SigningPayload.yaml b/models/SigningPayload.yaml index 429d14e..5b23367 100644 --- a/models/SigningPayload.yaml +++ b/models/SigningPayload.yaml @@ -16,10 +16,9 @@ description: | SigningPayload is signed by the client with the keypair associated with an address using the specified SignatureType. - [TODO] explain that signature_type is provided optionally - if there is a restriction. Otherwise, leave blank for default - or if multiple accepted (does not mean any signature type can - be used). + SignatureType can be optionally populated if there is + a restriction on the signature scheme that can be + used to sign the payload. type: object required: - address @@ -27,6 +26,9 @@ required: properties: address: type: string + description: | + The network-specific address of the account that should sign + the payload. hex_bytes: type: string signature_type: From 982f089be3aac3f2d4b0d099db45f763fe6b89eb Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 13:26:16 -0700 Subject: [PATCH 13/18] Add notes about signature schemes --- README.md | 20 ++++++++++++++++++++ api.yaml | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index a0c8d74..1c31d4f 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,26 @@ code from this specification. In the near future, we will update this section with tips and helpful links for writing a Construction API implementation. +## Decoupled Signature Schemes +CurveType and SignatureType are purposely decoupled as a curve could be used +with multiple signature types (i.e. `secp256k1:ECDSA` and `secp256k1:Schnorr`). + +### Missing CurveType or SignatureType +Unlike the Data API where there are no global type constraints (ex: you +can specify any operation type), the Construction API has a clearly +enumerated list of supported curves and signatures. Each one of these +items has a clearly specified format that all implementations should +expect to receive. + +If a curve or signature you are employing is not enumerated in the specification, +you will need to open a PR against the specification to add it along with the standard +format it will be represented in. + +It is up to the caller of a Construction API implementation to implement key generation +and signing for a particular CurveType:SignatureType. There is a `keys` package +in rosetta-sdk-go that is commonly used by callers and anyone +in the community can implement additional schemes there. + ## Deployment Although the Construction API is defined in the same interface as endpoints that are "online" (i.e. fetching a block with `/block`), it must be possible to deploy your Data API diff --git a/api.yaml b/api.yaml index 180ea99..ea56109 100644 --- a/api.yaml +++ b/api.yaml @@ -395,6 +395,13 @@ paths: and the response from `/construction/metadata`. It returns an unsigned transaction blob and a collection of payloads that must be signed by particular addresses using a certain SignatureType. + + The array of operations provided in transaction construction often times + can not specify all "effects" of a transaction (consider invoked transactions + in Ethereum). However, they can deterministically specify the "intent" + of the transaction, which is sufficient for construction. For this reason, + parsing the corresponding transaction in the Data API (when it lands on chain) + will contain a superset of whatever operations were provided during construction. operationId: constructionPayloads tags: - Construction From 8cda1ad3c61ec4b302bf26c57ac915b58f24ea76 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 13:30:39 -0700 Subject: [PATCH 14/18] Add crypto formats --- models/CurveType.yaml | 3 +++ models/SignatureType.yaml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/models/CurveType.yaml b/models/CurveType.yaml index 565be6c..7b8be02 100644 --- a/models/CurveType.yaml +++ b/models/CurveType.yaml @@ -14,6 +14,9 @@ description: | CurveType is the type of cryptographic curve associated with a PublicKey. + + * secp256k1 = SEC compressed 33-bytes. + * edwards25519 = y (255-bits) || x-sign-bit (32-bytes). type: string enum: - secp256k1 diff --git a/models/SignatureType.yaml b/models/SignatureType.yaml index 4d72b50..76acec1 100644 --- a/models/SignatureType.yaml +++ b/models/SignatureType.yaml @@ -14,6 +14,10 @@ description: | SignatureType is the type of a cryptographic signature. + + * ecdsa = r (32-bytes) || s (32-bytes) + * ecdsa_recovery = r (32-bytes) || s (32-bytes) || v (1-byte) + * ed25519 = R (32-byte) || s (32-bytes) type: string enum: - ecdsa From 0b14bbace248a89c9afc9e232c7faeaddb0a3bf3 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 14:04:06 -0700 Subject: [PATCH 15/18] Fix double space issue --- codegen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/codegen.sh b/codegen.sh index 57352c5..4cea615 100755 --- a/codegen.sh +++ b/codegen.sh @@ -35,5 +35,6 @@ OUTPUT_FILE=api.json swagger-cli bundle api.yaml -o "${OUTPUT_FILE}"; # Remove newlines from descriptions +sed "${SED_IFLAG[@]}" 's/\\n\\n/\\n/g' "${OUTPUT_FILE}"; sed "${SED_IFLAG[@]}" 's/\\n/ /g' "${OUTPUT_FILE}"; sed "${SED_IFLAG[@]}" 's/ "/"/g' "${OUTPUT_FILE}"; From e0d1558b61c950b7d97343f5d0dd964de4bcba1a Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 14:11:54 -0700 Subject: [PATCH 16/18] Add supported curvetypes and signaturetypes to README --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c31d4f..077965c 100644 --- a/README.md +++ b/README.md @@ -228,11 +228,20 @@ code from this specification. In the near future, we will update this section with tips and helpful links for writing a Construction API implementation. -## Decoupled Signature Schemes +### Supported CurveTypes +* secp256k1: 1SEC compressed 33-bytes. +* edwards25519 = y (255-bits) || x-sign-bit (32-bytes). + +### Supported SignatureTypes +* ecdsa = r (32-bytes) || s (32-bytes) +* ecdsa_recovery = r (32-bytes) || s (32-bytes) || v (1-byte) +* ed25519 = R (32-byte) || s (32-bytes) + +### Decoupled Signature Schemes CurveType and SignatureType are purposely decoupled as a curve could be used with multiple signature types (i.e. `secp256k1:ECDSA` and `secp256k1:Schnorr`). -### Missing CurveType or SignatureType +### Adding New CurveTypes or SignatureTypes Unlike the Data API where there are no global type constraints (ex: you can specify any operation type), the Construction API has a clearly enumerated list of supported curves and signatures. Each one of these From 5d3614082e603aa2f5795ebe28240789f2a7f73a Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 14:12:29 -0700 Subject: [PATCH 17/18] run make gen --- api.json | 589 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 569 insertions(+), 20 deletions(-) diff --git a/api.json b/api.json index f4517f8..ee24f43 100644 --- a/api.json +++ b/api.json @@ -1,9 +1,9 @@ { "openapi":"3.0.2", "info": { - "version":"1.3.1", + "version":"1.4.0", "title":"Rosetta", - "description":"A Standard for Blockchain Interaction", + "description":"Build Once. Integrate Your Blockchain Everywhere.", "license": { "name":"Apache 2.0", "url":"http://www.apache.org/licenses/LICENSE-2.0.html" @@ -13,7 +13,7 @@ "/network/list": { "post": { "summary":"Get List of Available Networks", - "description":"This endpoint returns a list of NetworkIdentifiers that the Rosetta server can handle.", + "description":"This endpoint returns a list of NetworkIdentifiers that the Rosetta server supports.", "operationId":"networkList", "tags": [ "Network" @@ -97,7 +97,7 @@ "/network/options": { "post": { "summary":"Get Network Options", - "description":"This endpoint returns the version information and allowed network-specific types for a NetworkIdentifier. Any NetworkIdentifier returned by /network/list should be accessible here. Because options are retrievable in the context of a NetworkIdentifier, it is possible to define unique options for each network.", + "description":"This endpoint returns the version information and allowed network-specific types for a NetworkIdentifier. Any NetworkIdentifier returned by /network/list should be accessible here. Because options are retrievable in the context of a NetworkIdentifier, it is possible to define unique options for each network.", "operationId":"networkOptions", "tags": [ "Network" @@ -181,7 +181,7 @@ "/block/transaction": { "post": { "summary":"Get a Block Transaction", - "description":"Get a transaction in a block by its Transaction Identifier. This endpoint should only be used when querying a node for a block does not return all transactions contained within it. All transactions returned by this endpoint must be appended to any transactions returned by the /block method by consumers of this data. Fetching a transaction by hash is considered an Explorer Method (which is classified under the Future Work section). Calling this endpoint requires reference to a BlockIdentifier because transaction parsing can change depending on which block contains the transaction. For example, in Bitcoin it is necessary to know which block contains a transaction to determine the destination of fee payments. Without specifying a block identifier, the node would have to infer which block to use (which could change during a re-org). Implementations that require fetching previous transactions to populate the response (ex: Previous UTXOs in Bitcoin) may find it useful to run a cache within the Rosetta server in the /data directory (on a path that does not conflict with the node).", + "description":"Get a transaction in a block by its Transaction Identifier. This endpoint should only be used when querying a node for a block does not return all transactions contained within it. All transactions returned by this endpoint must be appended to any transactions returned by the /block method by consumers of this data. Fetching a transaction by hash is considered an Explorer Method (which is classified under the Future Work section). Calling this endpoint requires reference to a BlockIdentifier because transaction parsing can change depending on which block contains the transaction. For example, in Bitcoin it is necessary to know which block contains a transaction to determine the destination of fee payments. Without specifying a block identifier, the node would have to infer which block to use (which could change during a re-org). Implementations that require fetching previous transactions to populate the response (ex: Previous UTXOs in Bitcoin) may find it useful to run a cache within the Rosetta server in the /data directory (on a path that does not conflict with the node).", "operationId":"blockTransaction", "tags": [ "Block" @@ -265,7 +265,7 @@ "/mempool/transaction": { "post": { "summary":"Get a Mempool Transaction", - "description":"Get a transaction in the mempool by its Transaction Identifier. This is a separate request than fetching a block transaction (/block/transaction) because some blockchain nodes need to know that a transaction query is for something in the mempool instead of a transaction in a block. Transactions may not be fully parsable until they are in a block (ex: may not be possible to determine the fee to pay before a transaction is executed). On this endpoint, it is ok that returned transactions are only estimates of what may actually be included in a block.", + "description":"Get a transaction in the mempool by its Transaction Identifier. This is a separate request than fetching a block transaction (/block/transaction) because some blockchain nodes need to know that a transaction query is for something in the mempool instead of a transaction in a block. Transactions may not be fully parsable until they are in a block (ex: may not be possible to determine the fee to pay before a transaction is executed). On this endpoint, it is ok that returned transactions are only estimates of what may actually be included in a block.", "operationId":"mempoolTransaction", "tags": [ "Mempool" @@ -307,7 +307,7 @@ "/account/balance": { "post": { "summary":"Get an Account Balance", - "description":"Get an array of all Account Balances for an Account Identifier and the Block Identifier at which the balance lookup was performed. Some consumers of account balance data need to know at which block the balance was calculated to reconcile account balance changes. To get all balances associated with an account, it may be necessary to perform multiple balance requests with unique Account Identifiers. If the client supports it, passing nil AccountIdentifier metadata to the request should fetch all balances (if applicable). It is also possible to perform a historical balance lookup (if the server supports it) by passing in an optional BlockIdentifier.", + "description":"Get an array of all Account Balances for an Account Identifier and the Block Identifier at which the balance lookup was performed. Some consumers of account balance data need to know at which block the balance was calculated to reconcile account balance changes. To get all balances associated with an account, it may be necessary to perform multiple balance requests with unique Account Identifiers. If the client supports it, passing nil AccountIdentifier metadata to the request should fetch all balances (if applicable). It is also possible to perform a historical balance lookup (if the server supports it) by passing in an optional BlockIdentifier.", "operationId":"accountBalance", "tags": [ "Account" @@ -346,10 +346,94 @@ } } }, + "/construction/derive": { + "post": { + "summary":"Derive an Address from a PublicKey", + "description":"Derive returns the network-specific address associated with a public key. Blockchains that require an on-chain action to create an account should not implement this method.", + "operationId":"constructionDerive", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionDeriveRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionDeriveResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, + "/construction/preprocess": { + "post": { + "summary":"Create a Request to Fetch Metadata", + "description":"Preprocess is called prior to `/construction/payloads` to construct a request for any metadata that is needed for transaction construction given (i.e. account nonce). The request returned from this method will be used by the caller (in a different execution environment) to call the `/construction/metadata` endpoint.", + "operationId":"constructionPreprocess", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionPreprocessRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionPreprocessResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, "/construction/metadata": { "post": { - "summary":"Get Transaction Construction Metadata", - "description":"Get any information required to construct a transaction for a specific network. Metadata returned here could be a recent hash to use, an account sequence number, or even arbitrary chain state. It is up to the client to correctly populate the options object with any network-specific details to ensure the correct metadata is retrieved. It is important to clarify that this endpoint should not pre-construct any transactions for the client (this should happen in the SDK). This endpoint is left purposely unstructured because of the wide scope of metadata that could be required. In a future version of the spec, we plan to pass an array of Rosetta Operations to specify which metadata should be received and to create a transaction in an accompanying SDK. This will help to insulate the client from chain-specific details that are currently required here.", + "summary":"Get Metadata for Transaction Construction", + "description":"Get any information required to construct a transaction for a specific network. Metadata returned here could be a recent hash to use, an account sequence number, or even arbitrary chain state. The request used when calling this endpoint is often created by calling `/construction/preprocess` in an offline environment. It is important to clarify that this endpoint should not pre-construct any transactions for the client (this should happen in `/construction/payloads`). This endpoint is left purposely unstructured because of the wide scope of metadata that could be required.", "operationId":"constructionMetadata", "tags": [ "Construction" @@ -388,10 +472,178 @@ } } }, + "/construction/payloads": { + "post": { + "summary":"Generate an Unsigned Transaction and Signing Payloads", + "description":"Payloads is called with an array of operations and the response from `/construction/metadata`. It returns an unsigned transaction blob and a collection of payloads that must be signed by particular addresses using a certain SignatureType. The array of operations provided in transaction construction often times can not specify all \"effects\" of a transaction (consider invoked transactions in Ethereum). However, they can deterministically specify the \"intent\" of the transaction, which is sufficient for construction. For this reason, parsing the corresponding transaction in the Data API (when it lands on chain) will contain a superset of whatever operations were provided during construction.", + "operationId":"constructionPayloads", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionPayloadsRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionPayloadsResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, + "/construction/combine": { + "post": { + "summary":"Create Network Transaction from Signatures", + "description":"Combine creates a network-specific transaction from an unsigned transaction and an array of provided signatures. The signed transaction returned from this method will be sent to the `/construction/submit` endpoint by the caller.", + "operationId":"constructionCombine", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionCombineRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionCombineResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, + "/construction/parse": { + "post": { + "summary":"Parse a Transaction", + "description":"Parse is called on both unsigned and signed transactions to understand the intent of the formulated transaction. This is run as a sanity check before signing (after `/construction/payloads`) and before broadcast (after `/construction/combine`). ", + "operationId":"constructionParse", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionParseRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionParseResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, + "/construction/hash": { + "post": { + "summary":"Get the Hash of a Signed Transaction", + "description":"TransactionHash returns the network-specific transaction hash for a signed transaction.", + "operationId":"constructionHash", + "tags": [ + "Construction" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionHashRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/ConstructionHashResponse" + } + } + } + }, + "default": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, "/construction/submit": { "post": { "summary":"Submit a Signed Transaction", - "description":"Submit a pre-signed transaction to the node. This call should not block on the transaction being included in a block. Rather, it should return immediately with an indication of whether or not the transaction was included in the mempool. The transaction submission response should only return a 200 status if the submitted transaction could be included in the mempool. Otherwise, it should return an error.", + "description":"Submit a pre-signed transaction to the node. This call should not block on the transaction being included in a block. Rather, it should return immediately with an indication of whether or not the transaction was included in the mempool. The transaction submission response should only return a 200 status if the submitted transaction could be included in the mempool. Otherwise, it should return an error.", "operationId":"constructionSubmit", "tags": [ "Construction" @@ -531,14 +783,14 @@ ], "properties": { "index": { - "description":"The operation index is used to ensure each operation has a unique identifier within a transaction. To clarify, there may not be any notion of an operation index in the blockchain being described.", + "description":"The operation index is used to ensure each operation has a unique identifier within a transaction. To clarify, there may not be any notion of an operation index in the blockchain being described.", "type":"integer", "format":"int64", "minimum": 0, "example": 1 }, "network_index": { - "description":"Some blockchains specify an operation index that is essential for client use. For example, Bitcoin uses a network_index to identify which UTXO was used in a transaction. network_index should not be populated if there is no notion of an operation index in a blockchain (typically most account-based blockchains).", + "description":"Some blockchains specify an operation index that is essential for client use. For example, Bitcoin uses a network_index to identify which UTXO was used in a transaction. network_index should not be populated if there is no notion of an operation index in a blockchain (typically most account-based blockchains).", "type":"integer", "format":"int64", "minimum": 0, @@ -580,7 +832,7 @@ "example":"0x6b175474e89094c44da98b954eedeac495271d0f" }, "metadata": { - "description":"If the SubAccount address is not sufficient to uniquely specify a SubAccount, any other identifying information can be stored here. It is important to note that two SubAccounts with identical addresses but differing metadata will not be considered equal by clients.", + "description":"If the SubAccount address is not sufficient to uniquely specify a SubAccount, any other identifying information can be stored here. It is important to note that two SubAccounts with identical addresses but differing metadata will not be considered equal by clients.", "type":"object" } } @@ -659,7 +911,7 @@ "$ref":"#/components/schemas/OperationIdentifier" }, "related_operations": { - "description":"Restrict referenced related_operations to identifier indexes < the current operation_identifier.index. This ensures there exists a clear DAG-structure of relations. Since operations are one-sided, one could imagine relating operations in a single transfer or linking operations in a call tree.", + "description":"Restrict referenced related_operations to identifier indexes < the current operation_identifier.index. This ensures there exists a clear DAG-structure of relations. Since operations are one-sided, one could imagine relating operations in a single transfer or linking operations in a call tree.", "type":"array", "items": { "$ref":"#/components/schemas/OperationIdentifier" @@ -679,7 +931,7 @@ "example":"Transfer" }, "status": { - "description":"The network-specific status of the operation. Status is not defined on the transaction object because blockchains with smart contracts may have transactions that partially apply. Blockchains with atomic transactions (all operations succeed or all operations fail) will have the same status for each operation.", + "description":"The network-specific status of the operation. Status is not defined on the transaction object because blockchains with smart contracts may have transactions that partially apply. Blockchains with atomic transactions (all operations succeed or all operations fail) will have the same status for each operation.", "type":"string", "example":"Reverted" }, @@ -707,7 +959,7 @@ ], "properties": { "value": { - "description":"Value of the transaction in atomic units represented as an arbitrary-sized signed integer. For example, 1 BTC would be represented by a value of 100000000.", + "description":"Value of the transaction in atomic units represented as an arbitrary-sized signed integer. For example, 1 BTC would be represented by a value of 100000000.", "type":"string", "example":"1238089899992" }, @@ -733,14 +985,14 @@ "example":"BTC" }, "decimals": { - "description":"Number of decimal places in the standard unit representation of the amount. For example, BTC has 8 decimals. Note that it is not possible to represent the value of some currency in atomic units that is not base 10.", + "description":"Number of decimal places in the standard unit representation of the amount. For example, BTC has 8 decimals. Note that it is not possible to represent the value of some currency in atomic units that is not base 10.", "type":"integer", "format":"int32", "minimum": 0, "example": 8 }, "metadata": { - "description":"Any additional information related to the currency itself. For example, it would be useful to populate this object with the contract address of an ERC-20 token.", + "description":"Any additional information related to the currency itself. For example, it would be useful to populate this object with the contract address of an ERC-20 token.", "type":"object", "example": { "Issuer":"Satoshi" @@ -839,7 +1091,7 @@ "type":"string" }, "successful": { - "description":"An Operation is considered successful if the Operation.Amount should affect the Operation.Account. Some blockchains (like Bitcoin) only include successful operations in blocks but other blockchains (like Ethereum) include unsuccessful operations that incur a fee. To reconcile the computed balance from the stream of Operations, it is critical to understand which Operation.Status indicate an Operation is successful and should affect an Account.", + "description":"An Operation is considered successful if the Operation.Amount should affect the Operation.Account. Some blockchains (like Bitcoin) only include successful operations in blocks but other blockchains (like Ethereum) include unsuccessful operations that incur a fee. To reconcile the computed balance from the stream of Operations, it is critical to understand which Operation.Status indicate an Operation is successful and should affect an Account.", "type":"boolean" } }, @@ -855,6 +1107,84 @@ "minimum": 0, "example": 1582833600000 }, + "PublicKey": { + "description":"PublicKey contains a public key byte array for a particular CurveType encoded in hex. Note that there is no PrivateKey struct as this is NEVER the concern of an implementation.", + "type":"object", + "required": [ + "hex_bytes", + "curve_type" + ], + "properties": { + "hex_bytes": { + "type":"string", + "description":"Hex-encoded public key bytes in the format specified by the CurveType." + }, + "curve_type": { + "$ref":"#/components/schemas/CurveType" + } + } + }, + "CurveType": { + "description":"CurveType is the type of cryptographic curve associated with a PublicKey. * secp256k1 = SEC compressed 33-bytes. * edwards25519 = y (255-bits) || x-sign-bit (32-bytes).", + "type":"string", + "enum": [ + "secp256k1", + "edwards25519" + ] + }, + "SigningPayload": { + "description":"SigningPayload is signed by the client with the keypair associated with an address using the specified SignatureType. SignatureType can be optionally populated if there is a restriction on the signature scheme that can be used to sign the payload.", + "type":"object", + "required": [ + "address", + "hex_bytes" + ], + "properties": { + "address": { + "type":"string", + "description":"The network-specific address of the account that should sign the payload." + }, + "hex_bytes": { + "type":"string" + }, + "signature_type": { + "$ref":"#/components/schemas/SignatureType" + } + } + }, + "Signature": { + "description":"Signature contains the payload that was signed, the public keys of the keypairs used to produce the signature, the signature (encoded in hex), and the SignatureType. PublicKey is often times not known during construction of the signing payloads but may be needed to combine signatures properly.", + "type":"object", + "required": [ + "signing_payload", + "public_key", + "signature_type", + "hex_bytes" + ], + "properties": { + "signing_payload": { + "$ref":"#/components/schemas/SigningPayload" + }, + "public_key": { + "$ref":"#/components/schemas/PublicKey" + }, + "signature_type": { + "$ref":"#/components/schemas/SignatureType" + }, + "hex_bytes": { + "type":"string" + } + } + }, + "SignatureType": { + "description":"SignatureType is the type of a cryptographic signature. * ecdsa = r (32-bytes) || s (32-bytes) * ecdsa_recovery = r (32-bytes) || s (32-bytes) || v (1-byte) * ed25519 = R (32-byte) || s (32-bytes)", + "type":"string", + "enum": [ + "ecdsa", + "ecdsa_recovery", + "ed25519" + ] + }, "AccountBalanceRequest": { "description":"An AccountBalanceRequest is utilized to make a balance request on the /account/balance endpoint. If the block_identifier is populated, a historical balance query should be performed.", "type":"object", @@ -1130,7 +1460,7 @@ } }, "ConstructionMetadataResponse": { - "description":"The ConstructionMetadataResponse returns network-specific metadata used for transaction construction. It is likely that the client will not inspect this metadata before passing it to a client SDK that uses it for construction.", + "description":"The ConstructionMetadataResponse returns network-specific metadata used for transaction construction.", "type":"object", "required": [ "metadata" @@ -1145,6 +1475,225 @@ } } }, + "ConstructionDeriveRequest": { + "description":"ConstructionDeriveRequest is passed to the `/construction/derive` endpoint. Network is provided in the request because some blockchains have different address formats for different networks. Metadata is provided in the request because some blockchains allow for multiple address types (i.e. different address for validators vs normal accounts).", + "type":"object", + "required": [ + "network_identifier", + "public_key" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "public_key": { + "$ref":"#/components/schemas/PublicKey" + }, + "metadata": { + "type":"object" + } + } + }, + "ConstructionDeriveResponse": { + "description":"ConstructionDeriveResponse is returned by the `/construction/derive` endpoint.", + "type":"object", + "required": [ + "address" + ], + "properties": { + "address": { + "type":"string", + "description":"Address in network-specific format." + }, + "metadata": { + "type":"object" + } + } + }, + "ConstructionPreprocessRequest": { + "description":"ConstructionPreprocessRequest is passed to the `/construction/preprocess` endpoint so that a Rosetta implementation can determine which metadata it needs to request for construction.", + "type":"object", + "required": [ + "network_identifier", + "operations" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "operations": { + "type":"array", + "items": { + "$ref":"#/components/schemas/Operation" + } + }, + "metadata": { + "type":"object" + } + } + }, + "ConstructionPreprocessResponse": { + "description":"ConstructionPreprocessResponse contains the request that will be sent directly to `/construction/metadata`. If it is not necessary to make a request to `/construction/metadata`, options should be null.", + "type":"object", + "properties": { + "options": { + "type":"object", + "description":"The options that will be sent directly to `/construction/metadata` by the caller." + } + } + }, + "ConstructionPayloadsRequest": { + "description":"ConstructionPayloadsRequest is the request to `/construction/payloads`. It contains the network, a slice of operations, and arbitrary metadata that was returned by the call to `/construction/metadata`.", + "type":"object", + "required": [ + "network_identifier", + "operations" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "operations": { + "type":"array", + "items": { + "$ref":"#/components/schemas/Operation" + } + }, + "metadata": { + "type":"object" + } + } + }, + "ConstructionPayloadsResponse": { + "description":"ConstructionTransactionResponse is returned by `/construction/payloads`. It contains an unsigned transaction blob (that is usually needed to construct the a network transaction from a collection of signatures) and an array of payloads that must be signed by the caller.", + "type":"object", + "required": [ + "unsigned_transaction", + "payloads" + ], + "properties": { + "unsigned_transaction": { + "type":"string" + }, + "payloads": { + "type":"array", + "items": { + "$ref":"#/components/schemas/SigningPayload" + } + } + } + }, + "ConstructionCombineRequest": { + "description":"ConstructionCombineRequest is the input to the `/construction/combine` endpoint. It contains the unsigned transaction blob returned by `/construction/payloads` and all required signatures to create a network transaction.", + "type":"object", + "required": [ + "network_identifier", + "unsigned_transaction", + "signatures" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "unsigned_transaction": { + "type":"string" + }, + "signatures": { + "type":"array", + "items": { + "$ref":"#/components/schemas/Signature" + } + } + } + }, + "ConstructionCombineResponse": { + "description":"ConstructionCombineResponse is returned by `/construction/combine`. The network payload will be sent directly to the `construction/submit` endpoint.", + "type":"object", + "required": [ + "signed_transaction" + ], + "properties": { + "signed_transaction": { + "type":"string" + } + } + }, + "ConstructionParseRequest": { + "description":"ConstructionParseRequest is the input to the `/construction/parse` endpoint. It allows the caller to parse either an unsigned or signed transaction.", + "type":"object", + "required": [ + "network_identifier", + "signed", + "transaction" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "signed": { + "type":"bool", + "description":"Signed is a boolean indicating whether the transaction is signed." + }, + "transaction": { + "type":"string", + "description":"This must be either the unsigned transaction blob returned by `/construction/payloads` or the signed transaction blob returned by `/construction/combine`." + } + } + }, + "ConstructionParseResponse": { + "description":"ConstructionParseResponse contains an array of operations that occur in a transaction blob. This should match the array of operations provided to `/construction/preprocess` and `/construction/payloads`.", + "type":"object", + "required": [ + "operations", + "signers" + ], + "properties": { + "operations": { + "type":"array", + "items": { + "$ref":"#/components/schemas/Operation" + } + }, + "signers": { + "description":"All signers of a particular transaction. If the transaction is unsigned, it should be empty.", + "type":"array", + "items": { + "type":"string" + } + }, + "metadata": { + "type":"object" + } + } + }, + "ConstructionHashRequest": { + "description":"ConstructionHashRequest is the input to the `/construction/hash` endpoint.", + "type":"object", + "required": [ + "network_identifier", + "signed_transaction" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "signed_transaction": { + "type":"string" + } + } + }, + "ConstructionHashResponse": { + "description":"ConstructionHashResponse is the output of the `/construction/hash` endpoint.", + "type":"object", + "required": [ + "transaction_hash" + ], + "properties": { + "transaction_hash": { + "type":"string" + } + } + }, "ConstructionSubmitRequest": { "description":"The transaction submission request includes a signed transaction.", "type":"object", From bae09dab3b79b69e4e7b258e574cb3d895e0b052 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Fri, 26 Jun 2020 14:15:05 -0700 Subject: [PATCH 18/18] nits --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 077965c..c16a3c0 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ Fortunately, it is possible (and encouraged) to build higher-level interfaces on top of these low-level endpoints to simplify development for integrators. For example, an interface developer may wish to automatically fetch metdata during their call to construct a transaction so users would not even -know there are multiple interactions occuring. One could also provide +know there are multiple interactions occurring. One could also provide a signing library with their higher-level interface so users do not need to use a detached signer. Here is an example of a simplified flow: ```