Skip to content

Commit 780f75a

Browse files
Merge pull request #264 from LedgerHQ/feature/sdk-generation
Automatic generation of the plugin SDK
2 parents 14fb8c8 + b6167ca commit 780f75a

File tree

4 files changed

+292
-3
lines changed

4 files changed

+292
-3
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: 'Commit and push if the version file has changed'
2+
3+
inputs:
4+
name:
5+
description: 'The name of the commiter'
6+
required: true
7+
default: 'github-actions[bot]'
8+
email:
9+
description: 'The email of the commiter'
10+
required: true
11+
default: 'github-actions[bot]@users.noreply.github.com'
12+
message:
13+
description: 'The commit message'
14+
required: true
15+
default: 'New release version(s)'
16+
files:
17+
description: 'The file(s) to add in the commit'
18+
required: true
19+
default: '*'
20+
directory:
21+
description: 'The directory in which the action will be performed'
22+
required: true
23+
default: '.'
24+
branch:
25+
description: 'Checkout (or create) on a specific branch before commit/push'
26+
required: true
27+
default: 'master'
28+
secret:
29+
description: 'A token allowing to push the commit on the repository'
30+
required: true
31+
default: '.'
32+
repository:
33+
description: 'The repository where to push'
34+
required: true
35+
default: ''
36+
37+
runs:
38+
using: 'composite'
39+
steps:
40+
- name: Commit the changes
41+
run: |
42+
git config --global user.name ${{ inputs.name }}
43+
ORIGIN="$(pwd)"
44+
cd ${{ inputs.directory }}
45+
git switch ${{ inputs.branch }} 2>/dev/null || git switch -c ${{ inputs.branch }}
46+
git status
47+
CHANGES="$(git status --porcelain ${{ inputs.files }})"
48+
if [ -z "${CHANGES}" ]; \
49+
then \
50+
echo "No changes, stopping now"; \
51+
cd ${origin} \
52+
exit 0; \
53+
fi
54+
echo -e "Changes:\n${CHANGES}"
55+
git add ${{ inputs.files }}
56+
git commit -am "${{ inputs.message }}"
57+
git log -n 2
58+
cd ${ORIGIN}
59+
shell: bash
60+
61+
- name: Push commit
62+
uses: ad-m/github-push-action@master
63+
with:
64+
github_token: ${{ inputs.secret }}
65+
branch: ${{ inputs.branch }}
66+
directory: ${{ inputs.directory }}
67+
repository: ${{ inputs.repository }}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Updating the SDK
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- master
8+
- develop
9+
10+
jobs:
11+
updating_SDK:
12+
name: Updating the SDK
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Clone
17+
uses: actions/checkout@v2
18+
with:
19+
# by default the action uses fetch-depth = 1, which creates
20+
# shallow repositories from which we can't push
21+
fetch-depth: 0
22+
submodules: recursive
23+
# needed, else the push inside the action will use default credentials
24+
# instead of provided ones
25+
persist-credentials: false
26+
27+
- name: Build new SDK
28+
run: python tools/build_sdk.py
29+
30+
- name: Extract branch name
31+
shell: bash
32+
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
33+
id: extract_branch
34+
35+
- name: Commit & push changes in the SDK if any
36+
uses: ./.github/actions/commit-changes
37+
with:
38+
name: 'ldg-github-ci'
39+
directory: ethereum-plugin-sdk
40+
branch: ${{ steps.extract_branch.outputs.branch }}
41+
message: "[update] Branch ${{ steps.extract_branch.outputs.branch }} | Commit ${GITHUB_SHA}"
42+
secret: ${{ secrets.CI_BOT_TOKEN }}
43+
repository: LedgerHQ/ethereum-plugin-sdk

Makefile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,8 @@ $(info INFO: Need to reinitialize git submodules)
202202
$(shell git submodule update --init)
203203
endif
204204

205-
# rebuild
206-
$(shell python3 ethereum-plugin-sdk/build_sdk.py)
207-
$(shell find ./ethereum-plugin-sdk -iname '*.h' -o -iname '*.c' | xargs clang-format-10 -i)
205+
# rebuild SDK
206+
$(shell python3 tools/build_sdk.py)
208207

209208
# check if a difference is noticed (fail if it happens in CI build)
210209
ifneq ($(shell git status | grep 'ethereum-plugin-sdk'),)

tools/build_sdk.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env python3
2+
3+
'''
4+
This script extract a few specific definitions from app-ethereum that are
5+
required to exchange information with ethereum external plugins.
6+
It should always be launched from app-ethereum:
7+
8+
python3 ethereum-plugin-sdk/build_sdk.py
9+
10+
'''
11+
12+
import os
13+
14+
15+
def extract_from_headers(sources, nodes_to_extract):
16+
cat_sources = []
17+
for source in sources:
18+
with open(source, 'r') as f:
19+
cat_sources += f.readlines()
20+
21+
sdk_body = []
22+
for key, values in nodes_to_extract.items():
23+
for value in values:
24+
node = []
25+
unclosed_curvy_brackets = False
26+
unclosed_parantheses = False
27+
for line in cat_sources:
28+
if key in line and value in line:
29+
node += [line]
30+
unclosed_curvy_brackets = line.count('{') - line.count('}')
31+
if unclosed_curvy_brackets == False:
32+
break
33+
elif (key == "fn" and value in line) or unclosed_parantheses:
34+
node += [line]
35+
unclosed_parantheses = line.find(")") == -1
36+
if unclosed_parantheses == False:
37+
break
38+
elif unclosed_curvy_brackets:
39+
node += [line]
40+
unclosed_curvy_brackets += line.count(
41+
'{') - line.count('}')
42+
if unclosed_curvy_brackets:
43+
continue
44+
else:
45+
break
46+
47+
sdk_body += [''.join(node)]
48+
49+
return '\n'.join(sdk_body)
50+
51+
52+
def extract_from_c_files(sources, nodes_to_extract):
53+
cat_sources = []
54+
for source in sources:
55+
with open(source, 'r') as f:
56+
cat_sources += f.readlines()
57+
58+
sdk_body = []
59+
for node_name in nodes_to_extract:
60+
node = []
61+
copying = False
62+
wait_curvy_bracket = True
63+
for line in cat_sources:
64+
if node_name in line:
65+
copying = True
66+
node += [line]
67+
unclosed_curvy_brackets = line.count('{') - line.count('}')
68+
elif copying:
69+
node += [line]
70+
unclosed_curvy_brackets += line.count('{') - line.count('}')
71+
if wait_curvy_bracket:
72+
wait_curvy_bracket = line.count('}') == 0
73+
if unclosed_curvy_brackets != 0 or wait_curvy_bracket:
74+
continue
75+
else:
76+
break
77+
78+
sdk_body += [''.join(node)]
79+
80+
return '\n'.join(sdk_body)
81+
82+
83+
def merge_headers(sources, nodes_to_extract):
84+
includes = [
85+
'#include "os.h"',
86+
'#include "cx.h"',
87+
'#include <stdbool.h>',
88+
'#include <string.h>'
89+
]
90+
91+
body = extract_from_headers(sources, nodes_to_extract)
92+
93+
eth_internals_h = '\n\n'.join([
94+
"/* This file is auto-generated, don't edit it */",
95+
"#pragma once",
96+
'\n'.join(includes),
97+
body
98+
])
99+
100+
with open("ethereum-plugin-sdk/include/eth_internals.h", 'w') as f:
101+
f.write(eth_internals_h)
102+
103+
104+
def copy_header(header_to_copy, merged_headers):
105+
106+
merged_headers = [os.path.basename(path) for path in merged_headers]
107+
108+
with open(header_to_copy, 'r') as f:
109+
source = f.readlines()
110+
111+
eth_plugin_interface_h = [
112+
"/* This file is auto-generated, don't edit it */\n"]
113+
for line in source:
114+
eth_plugin_interface_h += [line]
115+
for header in merged_headers:
116+
if header in line:
117+
del eth_plugin_interface_h[-1]
118+
break
119+
120+
# add '#include "eth_internals.h"'
121+
include_index = eth_plugin_interface_h.index('#include "cx.h"\n')
122+
eth_plugin_interface_h.insert(
123+
include_index+1, '#include "eth_internals.h"\n')
124+
125+
# dump to file
126+
with open("ethereum-plugin-sdk/include/eth_plugin_interface.h", 'w') as f:
127+
f.writelines(eth_plugin_interface_h)
128+
129+
130+
def merge_c_files(sources, nodes_to_extract):
131+
includes = [
132+
'#include "eth_internals.h"'
133+
]
134+
135+
body = extract_from_c_files(sources, nodes_to_extract)
136+
137+
eth_internals_h = '\n\n'.join([
138+
"/* This file is auto-generated, don't edit it */",
139+
'\n'.join(includes),
140+
body
141+
])
142+
143+
with open("ethereum-plugin-sdk/include/eth_internals.c", 'w') as f:
144+
f.write(eth_internals_h)
145+
146+
147+
if __name__ == "__main__":
148+
149+
# some nodes will be extracted from these headers and merged into a new one, copied to sdk
150+
headers_to_merge = [
151+
"src/tokens.h",
152+
"src/chainConfig.h",
153+
"src/utils.h",
154+
"src_common/ethUstream.h",
155+
"src_common/ethUtils.h",
156+
"src/shared_context.h",
157+
"src/eth_plugin_internal.h",
158+
"src/nft.h",
159+
]
160+
nodes_to_extract = {
161+
"#define": ["MAX_TICKER_LEN", "ADDRESS_LENGTH", "INT256_LENGTH", "WEI_TO_ETHER", "SELECTOR_SIZE", "PARAMETER_LENGTH", "RUN_APPLICATION", "COLLECTION_NAME_MAX_LEN"],
162+
"typedef enum": [],
163+
"typedef struct": ["tokenDefinition_t", "txInt256_t", "txContent_t", "nftInfo_t"],
164+
"typedef union": ["extraInfo_t"],
165+
"__attribute__((no_instrument_function)) inline": ["int allzeroes"],
166+
"const": ["HEXDIGITS"],
167+
"fn": ["void getEthAddressStringFromBinary", "void getEthAddressFromKey", "void getEthDisplayableAddress", "bool adjustDecimals", "bool uint256_to_decimal", "void amountToString", "void u64_to_string", "void copy_address", "void copy_parameter"]
168+
}
169+
merge_headers(headers_to_merge, nodes_to_extract)
170+
171+
# this header will be stripped from all #include related to previously merged headers, then copied to sdk
172+
copy_header("src/eth_plugin_interface.h", headers_to_merge)
173+
174+
# extract and merge function bodies
175+
c_files_to_merge = [
176+
"src/utils.c",
177+
"src_common/ethUtils.c",
178+
"src/eth_plugin_internal.c"
179+
]
180+
merge_c_files(c_files_to_merge, nodes_to_extract["fn"])

0 commit comments

Comments
 (0)