Skip to content

Commit

Permalink
WIP of make target migration
Browse files Browse the repository at this point in the history
  • Loading branch information
franklywatson committed Feb 6, 2025
1 parent 68b363a commit 57fbdf3
Show file tree
Hide file tree
Showing 3 changed files with 375 additions and 83 deletions.
53 changes: 35 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Set default values
# Configure environment constants
ACCOUNT_KEYS_FILENAME = "./account-keys.csv"
FLOW_JSON = "script/flow.json"
FLOW_JSON_NETWORK = "emulator"
FLOW_JSON_SIGNER = emulator-account
FLOW_JSON = script/flow.json
FLOW_JSON_NETWORK = localnet
FLOW_JSON_SIGNER = localnet-service-account
FLOW_CLI_FLAGS = -n $(FLOW_JSON_NETWORK) -f $(FLOW_JSON) --signer $(FLOW_JSON_SIGNER)
ROSETTA_NETWORK = "localnet"
ROSETTA_ENV = localnet
ROSETTA_HOST_URL = "http://127.0.0.1:8080"
COMPILER_FLAGS := CGO_CFLAGS="-O2 -D__BLST_PORTABLE__"

Expand All @@ -15,7 +15,6 @@ all: build
go-build:
${COMPILER_FLAGS} go build -o server cmd/server/server.go


.PHONY: gen-originator-account
gen-originator-account:
KEYS=$$(go run ./cmd/genkey/genkey.go -csv); \
Expand All @@ -37,19 +36,38 @@ gen-originator-account:
"hashAlgorithm": "SHA3_256", \
"privateKey": "'$$PRIVATE_KEY'" \
} \
}' "${FLOW_JSON}" > flow.json.tmp && mv flow.json.tmp "${FLOW_JSON}" || { echo "Failed to update flow.json with jq"; exit 1; }; \
}' "${FLOW_JSON}" > flow.json.tmp && mv flow.json.tmp "${FLOW_JSON}" || { echo "Failed to update ${FLOW_JSON} with jq"; exit 1; }; \
jq --arg address "$$address" '.originators += [$$address]' "${ROSETTA_ENV}.json" > env.json.tmp && mv env.json.tmp "${ROSETTA_ENV}.json"; \
echo "$(ACCOUNT_NAME),$$KEYS,$$address" >> $(ACCOUNT_KEYS_FILENAME); \
echo "Updated $(FLOW_JSON) and $(ACCOUNT_KEYS_FILENAME)";

.PHONY: fund-originator-accounts
fund-originator-accounts:
set -e; \
.PHONY: fund-accounts
fund-accounts:
while IFS=',' read -r col1 col2 col3 col4 address; do \
address=$$(echo $$address | xargs); \
echo "Seeding account with address: $$address"; \
flow transactions send script/cadence/transactions/basic-transfer.cdc $$address 100.0 $(FLOW_CLI_FLAGS); \
done < account-keys.csv

.PHONY: create-originator-derived-account
create-originator-derived-account:
set -e; \
KEYS=$$(go run ./cmd/genkey/genkey.go -csv); \
NEW_ACCOUNT_PUBLIC_FLOW_KEY=$$(echo $$KEYS | cut -d',' -f1); \
NEW_ACCOUNT_PUBLIC_ROSETTA_KEY=$$(echo $$KEYS | cut -d',' -f2); \
NEW_ACCOUNT_PRIVATE_KEY=$$(echo $$KEYS | cut -d',' -f3); \
echo "Created keys for $(NEW_ACCOUNT_NAME)"; \
echo "Flow Key: $$NEW_ACCOUNT_PUBLIC_FLOW_KEY"; \
echo "Rosetta Key: $$NEW_ACCOUNT_PUBLIC_ROSETTA_KEY"; \
echo "Private Key: $$NEW_ACCOUNT_PRIVATE_KEY"; \
ROOT_ORIGINATOR_ADDRESS=$$(grep '$(ORIGINATOR_NAME)' $(ACCOUNT_KEYS_FILENAME) | cut -d ',' -f 5); \
ROOT_ORIGINATOR_PUBLIC_KEY=$$(grep '$(ORIGINATOR_NAME)' $(ACCOUNT_KEYS_FILENAME) | cut -d ',' -f 5); \
ROOT_ORIGINATOR_PRIVATE_KEY=$$(grep '$(ORIGINATOR_NAME)' $(ACCOUNT_KEYS_FILENAME) | cut -d ',' -f 5); \
echo "Originator address: $$ROOT_ORIGINATOR_ADDRESS"; \
python3 rosetta_handler.py rosetta-create-derived-account $(ROSETTA_HOST_URL) $$ROOT_ORIGINATOR_ADDRESS $$ROOT_ORIGINATOR_PUBLIC_KEY $$ROOT_ORIGINATOR_PRIVATE_KEY $$NEW_ACCOUNT_PUBLIC_ROSETTA_KEY
#echo "$(NEW_ACCOUNT_NAME),$$KEYS,$$address" >> $(ACCOUNT_KEYS_FILENAME); \

.PHONY: build
build: go-build

Expand All @@ -72,13 +90,12 @@ proto:
@protoc --proto_path=model --go_out=model \
--go_opt=paths=source_relative model/model.proto

.PHONY: integration-test-cleanup
integration-test-cleanup:
rm -f flow.json
rm -f account-keys.csv
.PHONY: test-reset
test-reset:
rm -rf data
rm -rf flow-go

.PHONY: integration-test
integration-test:
python3 integration_test.py
.PHONY: test-cleanup
test-cleanup: test-reset
rm -f flow.json
rm -f account-keys.csv
rm -rf flow-go
219 changes: 219 additions & 0 deletions rosetta_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import json
import subprocess
import requests
import click # pip install click


@click.group()
def cli():
pass


# Shared function used internally but not standalone from CLI

def request_router(target_url, body):
headers = {'Content-type': 'application/json'}
r = requests.post(target_url, data=json.dumps(body), headers=headers)
return r.json()


def preprocess_transaction(rosetta_host_url, root_originator, operations, metadata=None):
endpoint = "/construction/preprocess"
target_url = rosetta_host_url + endpoint
data = {
"network_identifier": {
"blockchain": "flow",
"network": "localnet"
},
"operations": operations,
"metadata": {
"payer": root_originator
}
}
if metadata:
for key in metadata:
data["metadata"][key] = metadata[key]
return request_router(target_url, data)


def metadata_transaction(rosetta_host_url, options):
endpoint = "/construction/metadata"
target_url = rosetta_host_url + endpoint
data = {
"network_identifier": {
"blockchain": "flow",
"network": "localnet"
},
"options": options
}
return request_router(target_url, data)


def payloads_transaction(rosetta_host_url, operations, protobuf):
endpoint = "/construction/payloads"
target_url = rosetta_host_url + endpoint
data = {
"network_identifier": {
"blockchain": "flow",
"network": "localnet"
},
"operations": operations,
"metadata": {
"protobuf": protobuf
}
}
return request_router(target_url, data)


def combine_transaction(rosetta_host_url, unsigned_tx, root_originator, hex_bytes, rosetta_key, signed_tx):
endpoint = "/construction/combine"
target_url = rosetta_host_url + endpoint
data = {
"network_identifier": {
"blockchain": "flow",
"network": "localnet"
},
"unsigned_transaction": unsigned_tx,
"signatures": [
{
"signing_payload": {
"account_identifier": {
"address": root_originator
},
"address": root_originator,
"hex_bytes": hex_bytes,
"signature_type": "ecdsa"
},
"public_key": {
"hex_bytes": rosetta_key,
"curve_type": "secp256k1"
},
"signature_type": "ecdsa",
"hex_bytes": signed_tx
}
]
}
return request_router(target_url, data)


def submit_transaction(rosetta_host_url, signed_tx):
endpoint = "/construction/submit"
target_url = rosetta_host_url + endpoint
data = {
"network_identifier": {
"blockchain": "flow",
"network": "localnet"
},
"signed_transaction": signed_tx
}
return request_router(target_url, data)


######################################################################################
# Rosetta Construction helper functions callable from CLI
######################################################################################

@click.command()
@click.argument('rosetta_host_url', envvar='ROSETTA_HOST_URL', required=True)
@click.argument('root_originator_address', envvar='ROOT_ORIGINATOR_ADDRESS', required=True)
@click.argument('root_originator_public_rosetta_key', envvar='ROOT_ORIGINATOR_PUBLIC_ROSETTA_KEY', required=True)
@click.argument('root_originator_private_key', envvar='ROOT_ORIGINATOR_PRIVATE_KEY', required=True)
@click.argument('new_account_public_rosetta_key', envvar='NEW_ACCOUNT_PUBLIC_ROSETTA_KEY', required=True)
def rosetta_create_derived_account(rosetta_host_url, root_originator_address, root_originator_public_rosetta_key,
root_originator_private_key, new_account_public_rosetta_key):
print("Enter create: " + root_originator_address + ", new: " + new_account_public_rosetta_key)
transaction = "create_account"
metadata = {"public_key": new_account_public_rosetta_key}
operations = [
{
"type": transaction,
"operation_identifier": {
"index": 0
},
"metadata": metadata
}
]
preprocess_response = preprocess_transaction(rosetta_host_url, root_originator_address, operations)
print(preprocess_response)
metadata_response = metadata_transaction(rosetta_host_url, preprocess_response["options"])
payloads_response = payloads_transaction(rosetta_host_url, operations, metadata_response["metadata"]["protobuf"])
hex_bytes = payloads_response["payloads"][0]["hex_bytes"]
unsigned_tx = payloads_response["unsigned_transaction"]
sign_tx_cmd = "go run cmd/sign/sign.go " + root_originator_private_key + " " + hex_bytes
result = subprocess.run(sign_tx_cmd.split(" "), stdout=subprocess.PIPE)
signed_tx = result.stdout.decode('utf-8')[:-1]
combine_response = combine_transaction(rosetta_host_url, unsigned_tx, root_originator_address, hex_bytes,
root_originator_public_rosetta_key, signed_tx)
submit_transaction_response = submit_transaction(rosetta_host_url, combine_response["signed_transaction"])
return submit_transaction_response["transaction_identifier"]["hash"]


@click.command()
@click.argument('rosetta_host_url', envvar='ROSETTA_HOST_URL', required=True)
@click.argument('root_originator_address', envvar='ROOT_ORIGINATOR_ADDRESS', required=True)
@click.argument('root_originator_public_rosetta_key', envvar='ROOT_ORIGINATOR_PUBLIC_ROSETTA_KEY', required=True)
@click.argument('root_originator_private_key', envvar='ROOT_ORIGINATOR_PRIVATE_KEY', required=True)
@click.argument('recipient_address', envvar='RECIPIENT', required=True)
@click.argument('amount', envvar='AMOUNT', required=True)
def rosetta_transfer_funds(rosetta_host_url, root_originator_address, root_originator_public_rosetta_key,
root_originator_private_key, recipient_address, amount, i=0):
transaction = "transfer"
operations = [
{
"type": transaction,
"operation_identifier": {
"index": i
},
"account": {
"address": root_originator_address
},
"amount": {
"currency": {
"decimals": 8,
"symbol": "FLOW"
},
"value": str(-1 * amount * 10 ** 7)
}
},
{
"type": transaction,
"operation_identifier": {
"index": i + 1
},
"related_operations": [
{
"index": i
}
],
"account": {
"address": recipient_address
},
"amount": {
"currency": {
"decimals": 8,
"symbol": "FLOW"
},
"value": str(amount * 10 ** 7)
}
}
]
preprocess_response = preprocess_transaction(rosetta_host_url, root_originator_address, operations)
metadata_response = metadata_transaction(rosetta_host_url, preprocess_response["options"])
payloads_response = payloads_transaction(rosetta_host_url, operations, metadata_response["metadata"]["protobuf"])
hex_bytes = payloads_response["payloads"][0]["hex_bytes"]
unsigned_tx = payloads_response["unsigned_transaction"]
sign_tx_cmd = "go run cmd/sign/sign.go " + root_originator_private_key + " " + hex_bytes
result = subprocess.run(sign_tx_cmd.split(" "), stdout=subprocess.PIPE)
signed_tx = result.stdout.decode('utf-8')[:-1]
combine_response = combine_transaction(rosetta_host_url, unsigned_tx, root_originator_address, hex_bytes,
root_originator_public_rosetta_key, signed_tx)
submit_transaction_response = submit_transaction(rosetta_host_url, combine_response["signed_transaction"])
return submit_transaction_response["transaction_identifier"]["hash"]


# CLI bindings
cli.add_command(rosetta_create_derived_account)
cli.add_command(rosetta_transfer_funds)

if __name__ == '__main__':
cli()
Loading

0 comments on commit 57fbdf3

Please sign in to comment.