Compare commits

..
Author SHA1 Message Date
nabarun 0e814bd4da Support custom build and run for NextJS app (#969)
Lint Checks / Run linter (push) Successful in 17s
Publish / Build and publish (push) Successful in 31s
Smoke Test / Run basic test suite (push) Successful in 1m54s
Webapp Test / Run webapp test suite (push) Successful in 2m2s
Deploy Test / Run deploy test suite (push) Successful in 2m48s
Database Test / Run database hosting test on kind/k8s (push) Successful in 7m53s
Container Registry Test / Run contaier registry hosting test on kind/k8s (push) Failing after 4m43s
External Stack Test / Run external stack test suite (push) Successful in 5m11s
Fixturenet-Laconicd-Test / Run Laconicd fixturenet and Laconic CLI tests (push) Successful in 16m15s
K8s Deploy Test / Run deploy test suite on kind/k8s (push) Successful in 7m21s
Part of https://www.notion.so/Laconic-Mainnet-Plan-1eca6b22d47280569cd0d1e6d711d949
For deploying frontend https://git.vdb.to/NasSharaf/laconic-deployer-frontend

Reviewed-on: #969
Reviewed-by: ashwin <ashwin@noreply.git.vdb.to>
Co-authored-by: Nabarun <nabarun@deepstacksoft.com>
Co-committed-by: Nabarun <nabarun@deepstacksoft.com>
2025-08-20 12:26:11 +00:00
5 changed files with 95 additions and 160 deletions
@@ -26,8 +26,14 @@ fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
WORK_DIR="${1:-/app}"
if [ -f "${WORK_DIR}/build-webapp.sh" ]; then
echo "Building webapp with ${WORK_DIR}/build-webapp.sh ..."
cd "${WORK_DIR}" || exit 1
./build-webapp.sh || exit 1
exit 0
fi
if [ -f "next.config.mjs" ]; then
NEXT_CONFIG_JS="next.config.mjs"
IMPORT_OR_REQUIRE="import"
@@ -30,36 +30,44 @@ fi
CERC_WEBAPP_FILES_DIR="${CERC_WEBAPP_FILES_DIR:-/app}"
cd "$CERC_WEBAPP_FILES_DIR"
"$SCRIPT_DIR/apply-runtime-env.sh" "`pwd`" .next .next-r
mv .next .next.old
mv .next-r/.next .
if [ -f "./run-webapp.sh" ]; then
echo "Running webapp with run-webapp.sh ..."
cd "${WORK_DIR}" || exit 1
./run-webapp.sh &
tpid=$!
wait $tpid
else
"$SCRIPT_DIR/apply-runtime-env.sh" "`pwd`" .next .next-r
mv .next .next.old
mv .next-r/.next .
if [ "$CERC_NEXTJS_SKIP_GENERATE" != "true" ]; then
jq -e '.scripts.cerc_generate' package.json >/dev/null
if [ $? -eq 0 ]; then
npm run cerc_generate > gen.out 2>&1 &
tail -f gen.out &
tpid=$!
if [ "$CERC_NEXTJS_SKIP_GENERATE" != "true" ]; then
jq -e '.scripts.cerc_generate' package.json >/dev/null
if [ $? -eq 0 ]; then
npm run cerc_generate > gen.out 2>&1 &
tail -f gen.out &
tpid=$!
count=0
generate_done="false"
while [ $count -lt $CERC_MAX_GENERATE_TIME ] && [ "$generate_done" == "false" ]; do
sleep 1
count=$((count + 1))
grep 'rendered as static' gen.out > /dev/null
if [ $? -eq 0 ]; then
generate_done="true"
count=0
generate_done="false"
while [ $count -lt $CERC_MAX_GENERATE_TIME ] && [ "$generate_done" == "false" ]; do
sleep 1
count=$((count + 1))
grep 'rendered as static' gen.out > /dev/null
if [ $? -eq 0 ]; then
generate_done="true"
fi
done
if [ $generate_done != "true" ]; then
echo "ERROR: 'npm run cerc_generate' not successful within CERC_MAX_GENERATE_TIME" 1>&2
exit 1
fi
done
if [ $generate_done != "true" ]; then
echo "ERROR: 'npm run cerc_generate' not successful within CERC_MAX_GENERATE_TIME" 1>&2
exit 1
kill $tpid $(ps -ef | grep node | grep next | grep generate | awk '{print $2}') 2>/dev/null
tpid=""
fi
kill $tpid $(ps -ef | grep node | grep next | grep generate | awk '{print $2}') 2>/dev/null
tpid=""
fi
fi
$CERC_BUILD_TOOL start . -- -p ${CERC_LISTEN_PORT:-80}
$CERC_BUILD_TOOL start . -- -p ${CERC_LISTEN_PORT:-80}
fi
@@ -342,17 +342,6 @@ def dump_known_requests(filename, requests, status="SEEN"):
help="Requests must have a minimum payment to be processed (in alnt)",
default=0,
)
@click.option(
"--atom-payment-address",
help="Cosmos ATOM address to receive payments",
default=None,
)
@click.option(
"--min-atom-payment",
help="Minimum required ATOM payment amount",
default=1,
type=float,
)
@click.option("--lrn", help="The LRN of this deployer.", required=True)
@click.option(
"--all-requests",
@@ -405,8 +394,6 @@ def command( # noqa: C901
recreate_on_deploy,
log_dir,
min_required_payment,
atom_payment_address,
min_atom_payment,
lrn,
config_upload_dir,
private_key_file,
@@ -643,8 +630,6 @@ def command( # noqa: C901
payment_address,
min_required_payment,
main_logger,
atom_payment_address,
min_atom_payment,
):
main_logger.log(f"{r.id}: Payment confirmed.")
requests_to_execute.append(r)
@@ -46,17 +46,6 @@ from stack_orchestrator.deploy.webapp.util import LaconicRegistryClient
help="List the minimum required payment (in alnt) to process a deployment request.",
default=0,
)
@click.option(
"--atom-payment-address",
help="The Cosmos ATOM address to which payments should be made.",
default=None,
)
@click.option(
"--min-atom-payment",
help="List the minimum required payment (in uatom) to process a deployment request.",
default="1000000uatom",
type=str,
)
@click.option(
"--dry-run",
help="Don't publish anything, just report what would be done.",
@@ -71,8 +60,6 @@ def command( # noqa: C901
lrn,
payment_address,
min_required_payment,
atom_payment_address,
min_atom_payment,
dry_run,
):
laconic = LaconicRegistryClient(laconic_config)
@@ -96,10 +83,6 @@ def command( # noqa: C901
webapp_deployer_record["record"][
"minimumPayment"
] = f"{min_required_payment}alnt"
if atom_payment_address:
webapp_deployer_record["record"]["atomPaymentAddress"] = atom_payment_address
webapp_deployer_record["record"]["minimumAtomPayment"] = min_atom_payment
if dry_run:
yaml.dump(webapp_deployer_record, sys.stdout)
+55 -102
View File
@@ -801,7 +801,7 @@ def skip_by_tag(r, include_tags, exclude_tags):
return False
def confirm_payment(laconic: LaconicRegistryClient, record, payment_address, min_amount, logger, atom_payment_address=None, atom_min_amount=None):
def confirm_payment(laconic: LaconicRegistryClient, record, payment_address, min_amount, logger):
req_owner = laconic.get_owner(record)
if req_owner == payment_address:
# No need to confirm payment if the sender and recipient are the same account.
@@ -811,114 +811,67 @@ def confirm_payment(laconic: LaconicRegistryClient, record, payment_address, min
logger.log(f"{record.id}: no payment tx info")
return False
# Try to verify as a laconic payment first
tx = laconic.get_tx(record.attributes.payment)
if tx:
if tx.code != 0:
logger.log(
f"{record.id}: payment tx {tx.hash} was not successful - code: {tx.code}, log: {tx.log}"
)
return False
if not tx:
logger.log(f"{record.id}: cannot locate payment tx")
return False
if tx.sender != req_owner:
logger.log(
f"{record.id}: payment sender {tx.sender} in tx {tx.hash} does not match deployment "
f"request owner {req_owner}"
)
return False
if tx.recipient != payment_address:
logger.log(
f"{record.id}: payment recipient {tx.recipient} in tx {tx.hash} does not match {payment_address}"
)
return False
pay_denom = "".join([i for i in tx.amount if not i.isdigit()])
if pay_denom != "alnt":
logger.log(
f"{record.id}: {pay_denom} in tx {tx.hash} is not an expected payment denomination"
)
return False
pay_amount = int("".join([i for i in tx.amount if i.isdigit()]))
if pay_amount < min_amount:
logger.log(
f"{record.id}: payment amount {tx.amount} is less than minimum {min_amount}"
)
return False
# Check if the payment was already used on a deployment
used = laconic.app_deployments(
{"deployer": record.attributes.deployer, "payment": tx.hash}, all=True
if tx.code != 0:
logger.log(
f"{record.id}: payment tx {tx.hash} was not successful - code: {tx.code}, log: {tx.log}"
)
if len(used):
# Fetch the app name from request record
used_request = laconic.get_record(used[0].attributes.request, require=True)
return False
# Check that payment was used for deployment of same application
if record.attributes.application != used_request.attributes.application:
logger.log(f"{record.id}: payment {tx.hash} already used on a different application deployment {used}")
return False
used = laconic.app_deployment_removals(
{"deployer": record.attributes.deployer, "payment": tx.hash}, all=True
if tx.sender != req_owner:
logger.log(
f"{record.id}: payment sender {tx.sender} in tx {tx.hash} does not match deployment "
f"request owner {req_owner}"
)
if len(used):
logger.log(
f"{record.id}: payment {tx.hash} already used on deployment removal {used}"
)
return False
if tx.recipient != payment_address:
logger.log(
f"{record.id}: payment recipient {tx.recipient} in tx {tx.hash} does not match {payment_address}"
)
return False
pay_denom = "".join([i for i in tx.amount if not i.isdigit()])
if pay_denom != "alnt":
logger.log(
f"{record.id}: {pay_denom} in tx {tx.hash} is not an expected payment denomination"
)
return False
pay_amount = int("".join([i for i in tx.amount if i.isdigit()]))
if pay_amount < min_amount:
logger.log(
f"{record.id}: payment amount {tx.amount} is less than minimum {min_amount}"
)
return False
# Check if the payment was already used on a deployment
used = laconic.app_deployments(
{"deployer": record.attributes.deployer, "payment": tx.hash}, all=True
)
if len(used):
# Fetch the app name from request record
used_request = laconic.get_record(used[0].attributes.request, require=True)
# Check that payment was used for deployment of same application
if record.attributes.application != used_request.attributes.application:
logger.log(f"{record.id}: payment {tx.hash} already used on a different application deployment {used}")
return False
return True
# If we get here, the transaction hash wasn't found in the laconic testnet
# Let's check if it's a valid Cosmos ATOM payment if configuration is available
if atom_payment_address:
logger.log(f"{record.id}: checking if payment is a valid Cosmos ATOM transaction")
try:
import requests
# Use the webapp-deployment-status-api to verify the ATOM payment
deployer_record = laconic.get_record(record.attributes.deployer)
if not deployer_record or not deployer_record.attributes.apiUrl:
logger.log(f"{record.id}: cannot find deployer API URL to verify ATOM payment")
return False
api_url = deployer_record.attributes.apiUrl
verify_url = f"{api_url}/verify/atom-payment"
# Make a request to the API to verify the ATOM payment
# Pass markAsUsed=true to prevent this transaction from being used again
response = requests.post(
verify_url,
json={
"txHash": record.attributes.payment,
"minAmount": atom_min_amount,
"markAsUsed": True
},
timeout=10
)
if response.status_code != 200:
logger.log(f"{record.id}: ATOM payment verification API request failed with status {response.status_code}")
return False
result = response.json()
if not result.get("valid", False):
logger.log(f"{record.id}: ATOM payment verification failed: {result.get('reason', 'unknown reason')}")
return False
# Payment is valid
logger.log(f"{record.id}: ATOM payment verified successfully, amount: {result.get('amount')} ATOM")
return True
except Exception as e:
logger.log(f"{record.id}: error verifying ATOM payment: {str(e)}")
return False
logger.log(f"{record.id}: payment tx {record.attributes.payment} not found in laconic testnet and ATOM payment verification not configured")
return False
used = laconic.app_deployment_removals(
{"deployer": record.attributes.deployer, "payment": tx.hash}, all=True
)
if len(used):
logger.log(
f"{record.id}: payment {tx.hash} already used on deployment removal {used}"
)
return False
return True
def confirm_auction(laconic: LaconicRegistryClient, record, deployer_lrn, payment_address, logger):