Skip to content

docs: add an example script to sign Rosetta transaction #372

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 70 additions & 37 deletions docs/docs/install-and-deploy/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,73 @@ Within root folder of the project there are example `.env` files, which can be c
- `.env.IntegrationTest` - Is used for integration tests with yaci devkit
- `.env.docker-compose` - Is used for standard docker-compose setup (Copy this file and adjusted it to your needs)

| Variable | Description | Default |
| ---------------------------- | ---------------------------- | ------------------------------------- |
| `LOG` | Log level | INFO |
| `NETWORK` | Network | mainnet |
| `MITHRIL_SYNC` | Sync from Mithril snapshot | true |
| `PROTOCOL_MAGIC` | Cardano protocol magic | 764824073 |
| `DB_IMAGE_NAME` | Postgres docker image name | postgres |
| `DB_IMAGE_TAG` | Postgres docker image tag | 14.11-bullseye |
| `DB_NAME` | Postgres database | rosetta-java |
| `DB_USER` | Postgres admin user | rosetta_db_admin |
| `DB_SECRET` | Postgres admin secret | weakpwd#123_d |
| `DB_HOST` | Postgres host | db |
| `DB_PORT` | Postgres port | 5432 |
| `DB_SCHEMA` | Database schema | mainnet |
| `DB_PATH` | Database path | /data |
| `CARDANO_NODE_HOST` | Cardano node host | cardano-node |
| `CARDANO_NODE_PORT` | Cardano node port | 3001 |
| `CARDANO_NODE_VERSION` | Cardano node version | 8.9.2 |
| `CARDANO_NODE_SUBMIT_HOST` | Cardano node submit api host | cardano-submit-api |
| `NODE_SUBMIT_API_PORT` | Cardano node submit api port | 8090 |
| `CARDANO_NODE_SOCKET_PATH` | Cardano node socket path | /node |
| `CARDANO_NODE_SOCKET` | Cardano node socket file | /node/node.socket |
| `CARDANO_NODE_DB` | Cardano node db path | /node/db |
| `CARDANO_CONFIG` | Cardano node config path | /config/mainnet |
| `API_DOCKER_IMAGE_TAG` | Docker Tag for API Image | main |
| `API_SPRING_PROFILES_ACTIVE` | Api spring profile | staging |
| `API_PORT` | Rosetta api exposed port | 8082 |
| `ROSETTA_VERSION` | Rosetta version | 1.4.13 |
| `TOPOLOGY_FILEPATH` | Topology file path | ./config/mainnet/topology.json |
| `GENESIS_SHELLEY_PATH` | Genesis file path | ./config/mainnet/shelley-genesis.json |
| `GENESIS_BYRON_PATH` | Genesis file path | ./config/mainnet/byron-genesis.json |
| `GENESIS_ALONZO_PATH ` | Genesis file path | ./config/mainnet/alonzo-genesis.json |
| `GENESIS_CONWAY_PATH` | Genesis file path | ./config/mainnet/conway-genesis.json |
| `INDEXER_DOCKER_IMAGE_TAG` | Yaci indexer Docker version | main |
| `PRUNING_ENABLED` | If pruning should be enabled | true |
| `YACI_SPRING_PROFILES` | Yaci indexer spring profile | postgres |
| `DEVKIT_ENABLED` | Devkit enabled | false |
| Variable | Description | Default | Notes |
| ---------------------------- | ---------------------------- | ------------------------------------- | ----- |
| `LOG` | Log level | INFO | added in release 1.0.0 |
| `NETWORK` | Network | mainnet | added in release 1.0.0 |
| `MITHRIL_SYNC` | Sync from Mithril snapshot | true | added in release 1.0.0 |
| `PROTOCOL_MAGIC` | Cardano protocol magic | 764824073 | added in release 1.0.0 |
| `DB_IMAGE_NAME` | Postgres docker image name | postgres | added in release 1.0.0 |
| `DB_IMAGE_TAG` | Postgres docker image tag | 14.11-bullseye | added in release 1.0.0 |
| `DB_NAME` | Postgres database | rosetta-java | added in release 1.0.0 |
| `DB_USER` | Postgres admin user | rosetta_db_admin | added in release 1.0.0 |
| `DB_SECRET` | Postgres admin secret | weakpwd#123_d | added in release 1.0.0 |
| `DB_HOST` | Postgres host | db | added in release 1.0.0 |
| `DB_PORT` | Postgres port | 5432 | added in release 1.0.0 |
| `DB_SCHEMA` | Database schema | mainnet | added in release 1.0.0 |
| `DB_PATH` | Database path | /data | added in release 1.0.0 |
| `CARDANO_NODE_HOST` | Cardano node host | cardano-node | added in release 1.0.0 |
| `CARDANO_NODE_PORT` | Cardano node port | 3001 | added in release 1.0.0 |
| `CARDANO_NODE_VERSION` | Cardano node version | 8.9.2 | added in release 1.0.0 |
| `CARDANO_NODE_SUBMIT_HOST` | Cardano node submit api host | cardano-submit-api | added in release 1.0.0 |
| `NODE_SUBMIT_API_PORT` | Cardano node submit api port | 8090 | added in release 1.0.0 |
| `CARDANO_NODE_SOCKET_PATH` | Cardano node socket path | /node | added in release 1.0.0 |
| `CARDANO_NODE_SOCKET` | Cardano node socket file | /node/node.socket | added in release 1.0.0 |
| `CARDANO_NODE_DB` | Cardano node db path | /node/db | added in release 1.0.0 |
| `CARDANO_CONFIG` | Cardano node config path | /config/mainnet | added in release 1.0.0 |
| `API_DOCKER_IMAGE_TAG` | Docker Tag for API Image | main | added in release 1.0.0 |
| `API_SPRING_PROFILES_ACTIVE` | Api spring profile | staging | added in release 1.0.0 |
| `API_PORT` | Rosetta api exposed port | 8082 | added in release 1.0.0 |
| `ROSETTA_VERSION` | Rosetta version | 1.4.13 | added in release 1.0.0 |
| `TOPOLOGY_FILEPATH` | Topology file path | ./config/mainnet/topology.json | added in release 1.0.0 |
| `GENESIS_SHELLEY_PATH` | Genesis file path | ./config/mainnet/shelley-genesis.json | added in release 1.0.0 |
| `GENESIS_BYRON_PATH` | Genesis file path | ./config/mainnet/byron-genesis.json | added in release 1.0.0 |
| `GENESIS_ALONZO_PATH ` | Genesis file path | ./config/mainnet/alonzo-genesis.json | added in release 1.0.0 |
| `GENESIS_CONWAY_PATH` | Genesis file path | ./config/mainnet/conway-genesis.json | added in release 1.0.0 |
| `INDEXER_DOCKER_IMAGE_TAG` | Yaci indexer Docker version | main | added in release 1.0.0 |
| `PRUNING_ENABLED` | If pruning should be enabled | false | added in release 1.0.0 |
| `PRUNING_INTERVAL` | The prunning interval in seconds | 600 | added in release 1.2.4 |
| `PRUNING_SAFE_BLOCKS` | The number of safe blocks to keep in the store | 2160 | added in release 1.2.4 |
| `YACI_SPRING_PROFILES` | Yaci indexer spring profile | postgres | added in release 1.0.0 |
| `DEVKIT_ENABLED` | Devkit enabled | false | added in release 1.0.0 |
| `YACI_HTTP_BASE_URL` | Yaci Indexer's URL | http://yaci-indexer:9095/api/v1 | added in release 1.2.1 |
| `YACI_INDEXER_PORT` | Yaci Indexer's port | 9095 | added in release 1.2.1 |
| `HTTP_CONNECT_TIMEOUT_SECONDS` | Yaci connection timeout in second | 5 | added in release 1.2.1 |
| `HTTP_REQUEST_TIMEOUT_SECONDS` | Yaci request timeout in second | 5 | added in release 1.2.1 |
| `API_DB_POOL_MIN_COUNT` | Minimum number of connections API<->DB | 12 | added in release 1.2.5 |
| `API_DB_POOL_MAX_COUNT` | Maximum number of connections API<->DB | 12 | added in release 1.2.5 |
| `API_DB_POOL_MAX_LIFETIME_MS` | Description | 2000000 | added in release 1.2.5 |
| `API_DB_POOL_CONNECTION_TIMEOUT_MS` | Connection time out in second | 100000 | added in release 1.2.5 |
| `API_DB_KEEP_ALIVE_MS` | Keep Alive in second | 60000 | added in release 1.2.5 |
| `API_DB_LEAK_CONNECTIONS_WARNING_MS` | Leak connection time in second | 60000 | added in release 1.2.5 |
| `API_DB_MONITOR_PERFORMANCE` | Monitor performance enable? | false | added in release 1.2.5 |
| `DB_POSTGRES_MAX_CONNECTIONS ` | Maximum concurrent database connections | 300 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_SHARED_BUFFERS ` | Memory for caching | 4GB (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_EFFECTIVE_CACHE_SIZE` | Disk cache size | 8GB (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_WORK_MEM` | Allocate memory per operation for query processing | 64MB (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_MAINTENANCE_WORK_MEM` | Allocate memory for maintenance tasks like index creation | 512GB (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_WAL_BUFFERS` | Allocate memory for writing-ahead log, buffering transactions | 512MB (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_CHECKPOINT_COMPLETION_TARGET` | Targets checkpoint completion | 0.7 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_RANDOM_PAGE_COST ` | Cost estimate for random disk page access | 1.3 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_EFFECTIVE_IO_CONCURRENCY ` | Concurrent I/O operation for table scans | 2 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_PARALLEL_TUPLE_COST` | Cost of processing each tuple in parallel queries | 0.05 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_PARALLEL_SETUP_COST` | Cost for initiating parallel query workers | 500 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_MAX_PARALLEL_WORKERS_PER_GATHER` | Limits parallel workers per query | 4 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_MAX_PARALLEL_WORKERS` | Total parallel workers across all queries | 8 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_SEQ_PAGE_COST ` | Cost estimate for sequential disk page access | 1.0 | added in release 1.2.6 |
| `DB_POSTGRES_JIT` | Disables Just-In-Time compilation to reduce overhead | off | added in release 1.2.6 |
| `DB_POSTGRES_BGWRITER_LRU_MAXPAGES` | Limits background writer to clean 50 pages per cycle | 100 (mid-level profile) | added in release 1.2.6 |
| `DB_POSTGRES_BGWRITER_DELAY` | Delay between background writer cycles | 200ms (mid-level profile) | added in release 1.2.6 |



23 changes: 23 additions & 0 deletions examples/typescript/sign-tx/sign_tx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# what is sign_tx.ts

## Purpose:

sign_tx.ts is written to sign Rosetta Transaction CBOR code

The input is a Rosetta CBOR code that could be either the transaction and envelope (starting with 82...) or the Rosetta transaction payload (starting with a4 or a5...).

The output is the CBOR code including the signature

## Usage

- Declare the variable `rosettaUnsignedTx` at line 14 and save the file

- Run the program (eg: `deno run --allow-all sign_tx.ts`)

- The result is a signed CBOR

Here is an example

$deno run --allow-all sign_tx.ts
Unsigned Transaction: 84a400818258202138e16c10911f1c0e264909b0c8e6af903e3370b2a8a75ebf5443081100ec71000182825839000743d16cfe3c4fcc0c11c2403bbc10dbc7ecdd4477e053481a368e7a06e2ae44dff6770dc0f4ada3cf4cf2605008e27aecdb332ad349fda71a7735940082581d60d6dbfa87f1054da9d47d612b82634eff44871c371554c8e6732d53f41b00000001dcd3c37f021a00028c81031a026c822aa0f5f6
Signed tx: 84a400d90102818258202138e16c10911f1c0e264909b0c8e6af903e3370b2a8a75ebf5443081100ec71000182825839000743d16cfe3c4fcc0c11c2403bbc10dbc7ecdd4477e053481a368e7a06e2ae44dff6770dc0f4ada3cf4cf2605008e27aecdb332ad349fda71a7735940082581d60d6dbfa87f1054da9d47d612b82634eff44871c371554c8e6732d53f41b00000001dcd3c37f021a00028c81031a026c822aa100d9010281825820a7e2d982519d6cbba39042b96ccf1d85f3ed78f3f48e9b4dff946ae08389388258409c225b2e7a6601fe971d2a609de468820567c1ed7454a5bca888c56d08a6b3f9316d91c13127003b82edb7fcb723d533aba79f08719bce4c3f6563cd53ba9002f5f6
76 changes: 76 additions & 0 deletions examples/typescript/sign-tx/sign_tx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Bip32PrivateKey, FixedTransaction, Transaction } from "@emurgo/cardano-serialization-lib-nodejs";
import { mnemonicToEntropy } from "bip39";
import { Buffer } from "node:buffer";
import { decode } from "cbor";

// Setting constants
const CBOR_ARRAY_PREFIX = "84";
const CBOR_ARRAY_SUFFIX = "a0f5f6";
const VALID_CBOR_MAP_PREFIXES = ["a4", "a5"];

// Configuration
const mnemonicPhrase = "key in your 24 words of your mnemonic here, words separated by spaces";
//const rosettaUnsignedTx = "a400818258202138e16c10911f1c0e264909b0c8e6af903e3370b2a8a75ebf5443081100ec71000182825839000743d16cfe3c4fcc0c11c2403bbc10dbc7ecdd4477e053481a368e7a06e2ae44dff6770dc0f4ada3cf4cf2605008e27aecdb332ad349fda71a7735940082581d60d6dbfa87f1054da9d47d612b82634eff44871c371554c8e6732d53f41b00000001dcd3c37f021a00028c81031a026c822a";
const rosettaUnsignedTx = "8278f26134303064393031303238313832353832306633383131613830386135326362393366616362303538393465363861323066333266333438663131366436626231306236613234616266306639306630373330313031383138323538333930303332656434626132643437393133393530653938346565326138313335653536323334333532326139346130636562383965363561663239396431343364646433613633383634303834346161646166303735383930303563616132336138316662336638616266363532346238613431613038313661343438303231613030303238366139303331613034383335366531a16a6f7065726174696f6e7381a6746f7065726174696f6e5f6964656e746966696572a265696e646578006d6e6574776f726b5f696e64657800676163636f756e74a16761646472657373786c616464725f74657374317170726668356a6c357a666b6c616b68636d65657a6b7376727830796c70366861613234706b356d7434746477326634386e6c7237646d70716767337666303632367134336366616c65703973386b6e6c30337772786e6c6c3664736c723777666a66616d6f756e74a26863757272656e6379a26673796d626f6c6341444168646563696d616c73066576616c75656a2d3133353836373132316b636f696e5f6368616e6765a26f636f696e5f6964656e746966696572a16a6964656e7469666965727842663338313161383038613532636239336661636230353839346536386132306633326633343866313136643662623130623661323461626630663930663037333a316b636f696e5f616374696f6e6a636f696e5f7370656e74667374617475736773756363657373647479706565696e707574";

// Function to get Rosetta Payload
function processRosettaPayload(unsignedTx: string): string | null {
if (VALID_CBOR_MAP_PREFIXES.some(prefix => unsignedTx.startsWith(prefix))) {
return `${CBOR_ARRAY_PREFIX}${unsignedTx}${CBOR_ARRAY_SUFFIX}`;
}

try {
const bytes = Buffer.from(unsignedTx, "hex");
const decodedData = decode(bytes) as (string | object)[];
if (decodedData.length > 0 && typeof decodedData[0] === "string") {
return `${CBOR_ARRAY_PREFIX}${decodedData[0]}${CBOR_ARRAY_SUFFIX}`;
}
} catch (error) {
console.error("Invalid Rosetta transaction format:", error);
}
return null;
}

// Retrieve payment/stake key pair from mnemonic function
function generateKeysFromMnemonic(mnemonic: string) {
const entropy = mnemonicToEntropy(mnemonic);
const rootKey = Bip32PrivateKey.from_bip39_entropy(Buffer.from(entropy, "hex"), Buffer.from(""));
const accountKey = rootKey.derive(harden(1852)).derive(harden(1815)).derive(harden(0));
return {
utxoPrivKey: accountKey.derive(0).derive(0),
// stakePrivKey: accountKey.derive(2).derive(0), //In some operations you need stakeSkey as well
};
}

// Sign transaction with payment vkey
function signTransaction(txBodyBytes: Buffer, privateKey: Bip32PrivateKey): string {
const tx = Transaction.from_bytes(txBodyBytes);
const txBody = tx.body();
const transaction = FixedTransaction.new_from_body_bytes(txBody.to_bytes());
transaction.sign_and_add_vkey_signature(privateKey.to_raw_key());
return transaction.to_hex();
}

// Main function
function main() {
const unsignedTxCborHex = processRosettaPayload(rosettaUnsignedTx);
if (!unsignedTxCborHex) {
console.error("Your Hex string is not in Rosetta-Java format.");
return;
}
console.log("Unsigned Transaction:", unsignedTxCborHex);

const { utxoPrivKey } = generateKeysFromMnemonic(mnemonicPhrase);
const txBytes = Buffer.from(unsignedTxCborHex, "hex");
const signedTxHex = signTransaction(txBytes, utxoPrivKey);
// in case your TX needs more than 1 key to sign, add signatures by using transaction.sign_and_add_vkey_signature
// eg: adding signature signed by stake key
// transaction.sign_and_add_vkey_signature(stakePrivKey.to_raw_key());
console.log("Signed Transaction:", signedTxHex);
}

function harden(num: number): number {
return 0x80000000 + num;
}

main();
Loading