From ac19eff06062e8725c4efb9e36ced8959bed2c09 Mon Sep 17 00:00:00 2001 From: Peter Harpending Date: Mon, 20 Apr 2026 14:32:59 -0700 Subject: [PATCH] worksish --- .gitignore | 1 + .gitmodules | 3 + Makefile | 42 ++++++++++++ README.md | 67 +++++++++++++++++-- .../gajumaru/data/gajumaru_defaults.json | 1 + gmconfig/localnet/gajumaru/gajumaru.json | 51 ++++++++++++++ gmconfig/mainnet/gajumaru/.gitkeep | 0 gmconfig/testnet/gajumaru/.gitkeep | 0 lib/gajumaru | 1 + rebar.config | 15 ++++- rebar.lock | 17 +++++ src/gmplugin_hello_app.erl | 33 +++++++++ 12 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 gmconfig/localnet/gajumaru/data/gajumaru_defaults.json create mode 100644 gmconfig/localnet/gajumaru/gajumaru.json create mode 100644 gmconfig/mainnet/gajumaru/.gitkeep create mode 100644 gmconfig/testnet/gajumaru/.gitkeep create mode 160000 lib/gajumaru create mode 100644 rebar.lock diff --git a/.gitignore b/.gitignore index df53f7d..cba9edc 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ logs *.iml rebar3.crashdump *~ +/gaj diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..34a2715 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/gajumaru"] + path = lib/gajumaru + url = https://git.qpq.swiss/QPQ-AG/gajumaru.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4c427de --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +APP_NAME = gmplugin_hello +GAJUMARU_LIB = lib/gajumaru +BUILD_DIR = $(GAJUMARU_LIB)/_build/prod/rel/gajumaru +TARGET_NETWORK = localnet + +# steps are +# 1. call rebar3 gm_plugin to build the plugin +# 2. build the node +# 3. start the node with a configuration where it knows it needs to load our plugin +# 4. run a shell in the node context + + +all: compile + +init: submodules + +submodules: + git submodule init + git submodule update + +compile: + rebar3 compile + +build-my-plugin: compile + rebar3 gm_plugin + +# adapted from gmp_ix +build-gm-with-my-plugin: build-my-plugin + cp _build/default/$(APP_NAME).ez $(GAJUMARU_LIB)/plugins + cd $(GAJUMARU_LIB) && make prod-build + cp -rvf gmconfig/$(TARGET_NETWORK)/gajumaru/* $(BUILD_DIR) + + +fresh-console: build-gm-with-my-plugin console + +console: + $(BUILD_DIR)/bin/gajumaru console + +clean: + rebar3 clean + cd $(GAJUMARU_LIB) && make prod-clean + rm -f $(GAJUMARU_LIB)/plugins/$(APP_NAME).ez diff --git a/README.md b/README.md index 353f925..39e61dd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,64 @@ -gmplugin_hello -===== +# `gmplugin_hello` -An OTP application +This is a minimal Gajumaru plugin. This is meant to be a minimal working +template on which development can occur immediately. -Build ------ +# Quickstart - $ rebar3 compile +## System Prereqs + +## After clone + +``` +make init +make build-gm-with-my-plugin +``` + +## Running + +``` +make fresh-console +``` + +``` +(gajumaru@localhost)1> gmplugin_hello_app:hello(). +"hello, world" +(gajumaru@localhost)2> gmplugin_hello_app:network_id(). +<<"localnet">> +(gajumaru@localhost)3> gmplugin_hello_app:height(). +{ok,1} +``` + + +# Questions + + +## What is a Gajumaru? + +In the context of this document, "Gajumaru" with no qualification means the +Erlang software that runs a gajumaru node. + +## What is a Gajumaru plugin? + +A Gajumaru plugin is an Erlang application that runs in the same Erlang process +context as `gajumaru`, meaning it can natively call `aeu_db:whatever`. + +## What is the point of a Gajumaru plugin? + +Let's say you're developing a point-of-sale app for your daughter's lemonade +stand. Your application needs to interact with Gajumaru in some way. You're +going to have your LemonPay app talk to your own local gajumaru node that +you're running on your old laptop on `192.168.2.1`. + +The idea here is that the portion of your LemonPay business logic that needs to +interact intimately with data on the chain should run in the relatively +frictionless Erlang-to-Erlang context of the gajumaru application. Then you +expose a service interface on port `9876` that is tailored specifically for +LemonPay. LemonPay talks to `192.168.2.1:9876`. + +## How does anything do anything? + +The important thing to understand is that **gajumaru starts your plugin**. + +Therefore, when you're developing and iterating on your plugin, you need to +have a way to start gajumaru, start your plugin, mess around with it. diff --git a/gmconfig/localnet/gajumaru/data/gajumaru_defaults.json b/gmconfig/localnet/gajumaru/data/gajumaru_defaults.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/gmconfig/localnet/gajumaru/data/gajumaru_defaults.json @@ -0,0 +1 @@ +{} diff --git a/gmconfig/localnet/gajumaru/gajumaru.json b/gmconfig/localnet/gajumaru/gajumaru.json new file mode 100644 index 0000000..f073fa1 --- /dev/null +++ b/gmconfig/localnet/gajumaru/gajumaru.json @@ -0,0 +1,51 @@ +{ + "logging": { + "levels": [ + { + "target": "console", + "level": "debug" + } + ] + }, + "chain" : { + "db_backend" : "rocksdb", + "persist" : true + }, + "governance" : { + "network_id" : "localnet" + }, + "system" : { + "dev_mode" : true, + "plugins" : [ + { + "name" : "gmplugin_hello" + } + ] + }, + "hard_forks" : { + "versions" : { + "1" : { + "height" : 0, + "type" : { + "on_demand" : { + "mining" : { + "autostart" : false + } + } + }, + "data" : { + "data" : [ + { "accounts" : { + "ak_4JJZNZynTy7RhTQBn7k9q6ZRehwLFPB1ncSQcyenZ3j3zYn6c" : 1000000000000000000000, + "ak_2PPgx59oeXLKL87jNkxE5wFY5hC3vNS5kXWFQbCoy3znMcDHo" : 1000000000000000000000, + "ak_2nyQQiU38XGDYdfU4Z9RXmyY5YBcPxbpnGGvvBs8i6CCgiJjAM" : 1000000000000000000000, + "ak_3AVVjGNmSQCT6bzUWjhhZYd3yaFWztzyVANx4QD9sFBRxAsGM" : 1000000000000000000000, + "ak_2GZCX7k6AorKpF59XYQVmNehBXM4BD1XWaP9WjeHFgcCzeUvRM" : 1000000000000000000000 + } + } + ] + } + } + } + } +} diff --git a/gmconfig/mainnet/gajumaru/.gitkeep b/gmconfig/mainnet/gajumaru/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/gmconfig/testnet/gajumaru/.gitkeep b/gmconfig/testnet/gajumaru/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/gajumaru b/lib/gajumaru new file mode 160000 index 0000000..752c8d0 --- /dev/null +++ b/lib/gajumaru @@ -0,0 +1 @@ +Subproject commit 752c8d0ae5546ce42e3ec1bd4326606459975e20 diff --git a/rebar.config b/rebar.config index 059fc27..b38b613 100644 --- a/rebar.config +++ b/rebar.config @@ -1,5 +1,18 @@ {erl_opts, [debug_info]}. -{deps, []}. + +% there's some bug somewhere... this list must be nonempty for some reason +{deps, [ + {gmserialization, {gm, gmserialization}} +]}. + +{project_apps_dir, "lib/gajumaru/apps"}. + +{plugins, [ + {gmplugin_rebar3, {git, "https://git.qpq.swiss/QPQ-AG/gmplugin_rebar3.git", {branch,"master"}}} + ]}. + +{gajumaru_root, {git, "https://git.qpq.swiss/QPQ-AG/gajumaru", "master"}}. + {shell, [ %% {config, "config/sys.config"}, diff --git a/rebar.lock b/rebar.lock new file mode 100644 index 0000000..27665c1 --- /dev/null +++ b/rebar.lock @@ -0,0 +1,17 @@ +{"1.2.0", +[{<<"base58">>, + {git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git", + {ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}, + 1}, + {<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},1}, + {<<"enacl">>, + {git,"https://git.qpq.swiss/QPQ-AG/enacl.git", + {ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}, + 1}, + {<<"gmserialization">>,{gm,gmserialization},0}]}. +[ +{pkg_hash,[ + {<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>}]}, +{pkg_hash_ext,[ + {<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>}]} +]. diff --git a/src/gmplugin_hello_app.erl b/src/gmplugin_hello_app.erl index 4143d73..b8f0de5 100644 --- a/src/gmplugin_hello_app.erl +++ b/src/gmplugin_hello_app.erl @@ -7,8 +7,16 @@ -behaviour(application). + -export([start/2, stop/1]). +% tests +-export([ + hello/0, + network_id/0, + height/0 +]). + start(_StartType, _StartArgs) -> gmplugin_hello_sup:start_link(). @@ -16,3 +24,28 @@ stop(_State) -> ok. %% internal functions + + +%% +-spec hello() -> string(). + +hello() -> + "hello, world". + + + +-spec network_id() -> binary(). + +network_id() -> + aec_governance:get_network_id(). + + + +-spec height() -> {ok, Height :: pos_integer()} + | {error, no_top_block}. + +height() -> + case aec_chain:top_height() of + undefined -> {error, no_top_block}; + Height -> {ok, Height} + end.