Skip to content
This repository was archived by the owner on Nov 9, 2022. It is now read-only.

Commit cd8384f

Browse files
authored
v1.0.0 (#86)
* Improve sync restart * Resolve cursor issue * Fix indexed tag query * Fix sub query whereIn * Resolve [POST] /tx issue * Manifest Middleware * Manifest Table SQL * Manifest, faster redirect * Update manifest prefix * Updated documentation * Added CORS middleware
1 parent f6d5d37 commit cd8384f

22 files changed

+829
-677
lines changed

.env.dev

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ DATABASE_PASSWORD=arweave
66
DATABASE_NAME=arweave
77

88
ENVIRONMENT=public
9-
MANIFESTS=0
10-
BIP39=0
119
PORT=3000
1210

1311
PARALLEL=4
@@ -21,4 +19,4 @@ CACHING=1
2119
CACHE_FOLDER=/gateway/cache
2220
CACHE_OFFSET=0
2321

24-
MANIFEST_PREFIX=http://localhost:3000
22+
MANIFEST_PREFIX=amp-gw.online

.env.docker

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ DATABASE_PASSWORD=arweave
66
DATABASE_NAME=arweave
77

88
ENVIRONMENT=public
9-
MANIFESTS=0
10-
BIP39=0
119
PORT=3000
1210

1311
PARALLEL=4
@@ -21,4 +19,4 @@ CACHING=1
2119
CACHE_FOLDER=/gateway/cache
2220
CACHE_OFFSET=0
2321

24-
MANIFEST_PREFIX=https://gateway.amplify.host
22+
MANIFEST_PREFIX=amp-gw.online

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ DATABASE_PASSWORD=arweave
3636
DATABASE_NAME=arweave
3737
3838
ENVIRONMENT=public
39-
MANIFESTS=0
40-
BIP39=0
4139
PORT=3000
4240
4341
PARALLEL=4
@@ -48,7 +46,7 @@ CACHING=1
4846
CACHE_FOLDER=/gateway/cache
4947
CACHE_OFFSET=0
5048
51-
MANIFEST_PREFIX=https://gateway.amplify.host
49+
MANIFEST_PREFIX=amp-gw.online
5250
```
5351

5452
Make sure you copy this configuration to `.env`.

bin/index.create.sh

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ CREATE INDEX "index_domain_transactions" ON transactions USING BTREE ("domain");
3434
CREATE INDEX "index_app_transactions" ON transactions USING BTREE ("app");
3535
--- Transaction App-Name Index
3636
CREATE INDEX "index_App-Name_transactions" ON transactions USING BTREE ("App-Name");
37+
--- Transactions created_at index
38+
CREATE INDEX "transactions_created_at" ON transactions USING BTREE ("created_at");
3739
3840
--- Tag Indices
3941
--- Tag Transaction Id Index

bin/manifest.table.sql

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CREATE TABLE manifest (
2+
"manifest_url" varchar(64),
3+
"manifest_id" varchar(64),
4+
"tx_id" varchar(64),
5+
"path" text,
6+
7+
PRIMARY KEY("manifest_id", "tx_id")
8+
);

docs/DEV.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ DATABASE_PASSWORD=arweave
5353
DATABASE_NAME=arweave
5454
5555
ENVIRONMENT=public
56-
MANIFESTS=0
57-
BIP39=0
5856
PORT=3000
5957
6058
PARALLEL=4
@@ -68,7 +66,7 @@ CACHING=1
6866
CACHE_FOLDER=/gateway/cache
6967
CACHE_OFFSET=0
7068
71-
MANIFEST_PREFIX=https://gateway.amplify.host
69+
MANIFEST_PREFIX=amp-gw.online
7270
```
7371

7472
Make sure you copy this configuration to `.env`.

docs/MANIFEST.md

+9-37
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,24 @@
11
# Transaction Manifests
22

3-
### Enabling Transaction Manifests
4-
5-
Transaction Manifests are important to prevent `CORS`. By default, manifests are disabled in the `.env` files. You can enable it by changing:
6-
7-
```bash
8-
MANIFESTS=0
9-
```
10-
11-
to
12-
13-
```bash
14-
MANIFESTS=1
15-
```
3+
Transaction manifests are only usable with a valid domain. Please make sure to have a valid domain with wildcard SSL enabled. You can use Let's Encrypt to configure a domain accordingly.
164

175
In order to effectively use manifests. You need to have domain wildcards pointing to your domain.
186

19-
### Using BIP39 or SHA256
7+
### Configuring Manifests
208

21-
There are two different types of transaction manifests subdomains. SHA256 and BIP39. You can enable SHA256 subdomains by changing your `.env` file to:
9+
In order to configure manifests, you need to change the `MANIFEST_PREFIX` environment variable. It should just be your domain name. Simply change it from:
2210

23-
```bash
24-
BIP39=0
11+
```conf
12+
MANIFEST_PREFIX=amp-gw.online
2513
```
2614

27-
You can enable BIP39 subdomains by changing the `.env` file to:
15+
to
2816

29-
```bash
30-
BIP39=1
17+
```conf
18+
MANIFEST_PREFIX=my-actual.domain
3119
```
3220

33-
## Manifests for Websites
34-
35-
Manifests are fairly simple for actual domains. Let's say own the domain `amplify.testing123`. Follow these steps to enable transaction manifests on your website.
36-
37-
1. Point your `@` record to your Gateway server.
38-
39-
- This would be an `A` record for an IP.
40-
41-
- This would be a `CNAME` record for a service's subdomain (ie: AWS EC2, Heroku)
42-
43-
2. Point your `*.amplify.testing123` record to your Gateway server. Follow the same rules as 1.
44-
45-
3. Test your Gateway endpoints
46-
47-
- Run `ping amplify.testing123`. Ensure it runs a valid response.
48-
49-
- Go to any transaction id on `amplify.testing123/[tx id]` and ensure it redirects to a valid transaction manifest path.
21+
Once configured and the Gateway points to the same domain. It should be good to go.
5022

5123
## Manifests for Development
5224

docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ CACHING=1
5151
CACHE_FOLDER=/gateway/cache
5252
CACHE_OFFSET=0
5353
54-
MANIFEST_PREFIX=https://gateway.amplify.host
54+
MANIFEST_PREFIX=amp-gw.online
5555
```
5656

5757
Make sure you copy this configuration to `.env`.

migrations/20200404025828_initialize.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ export async function up(knex: Knex) {
5353
table.timestamp('created_at').defaultTo(knex.fn.now());
5454

5555
table.primary(['tx_id', 'index'], 'pkey_tags');
56+
})
57+
.createTable('manifest', (table) => {
58+
table.string('manifest_url', 64).notNullable();
59+
table.string('manifest_id', 64).notNullable();
60+
table.string('tx_id', 64).notNullable();
61+
table.text('path').notNullable();
62+
63+
table.primary(['manifest_url', 'tx_id'], 'pkey_manifest');
5664
});
5765
}
5866

@@ -61,5 +69,6 @@ export async function down(knex: Knex) {
6169
.withSchema(process.env.ENVIRONMENT || 'public')
6270
.dropTableIfExists('transactions')
6371
.dropTableIfExists('blocks')
64-
.dropTableIfExists('tags');
72+
.dropTableIfExists('tags')
73+
.dropTableIfExists('manifest');
6574
}

package.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@arweave/gateway",
3-
"version": "0.11.3",
3+
"version": "1.0.0",
44
"main": "dist/src/Gateway.js",
55
"repository": "[email protected]:ArweaveTeam/gateway.git",
66
"author": "Arweave <[email protected]>",
@@ -34,6 +34,7 @@
3434
"bip39": "^3.0.3",
3535
"body-parser": "^1.19.0",
3636
"colors": "^1.4.0",
37+
"cors": "^2.8.5",
3738
"crypto-random-string": "^3.3.1",
3839
"detect-mocha": "^0.1.0",
3940
"dotenv": "^8.2.0",
@@ -47,8 +48,9 @@
4748
"graphql-fields": "^2.0.3",
4849
"js-sha256": "^0.9.0",
4950
"knex": "^0.21.17",
50-
"koi-logs": "https://github.com/open-koi/logs",
51+
"koi-logs": "https://github.com/koii-network/logs",
5152
"lodash": "^4.17.20",
53+
"mime-types": "^2.1.31",
5254
"moment": "^2.29.1",
5355
"morgan": "^1.10.0",
5456
"node-cron": "^2.0.3",
@@ -67,6 +69,7 @@
6769
"@types/express": "^4.17.11",
6870
"@types/graphql-fields": "^1.3.3",
6971
"@types/lodash": "^4.14.168",
72+
"@types/mime-types": "^2.1.0",
7073
"@types/mocha": "^8.2.1",
7174
"@types/morgan": "^1.9.2",
7275
"@types/node": "^14.14.22",

src/Gateway.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import 'colors';
22
import express, {Express} from 'express';
33
import {config} from 'dotenv';
4-
import {corsMiddleware} from './middleware/cors.middleware';
4+
import cors from 'cors';
55
import {jsonMiddleware} from './middleware/json.middleware';
66
import {logMiddleware} from './middleware/log.middleware';
7+
import {manifestMiddleware} from './middleware/manifest.middleware';
78
import {log} from './utility/log.utility';
89
import {sessionMiddleware, sessionPinningMiddleware} from './utility/session.utility';
910
import {graphServer} from './graphql/server.graphql';
1011
import {statusRoute} from './route/status.route';
12+
import {transactionRoute} from './route/transaction.route';
1113
import {syncRoute} from './route/sync.route';
1214
import {proxyRoute} from './route/proxy.route';
1315
import {dataRouteRegex, dataRoute} from './route/data.route';
@@ -22,12 +24,13 @@ export const app: Express = express();
2224
export function start() {
2325
app.set('trust proxy', 1);
2426

25-
app.use(corsMiddleware);
27+
app.use(cors());
2628
app.use(jsonMiddleware);
2729
app.use(logMiddleware);
2830
app.use(sessionMiddleware);
2931
app.use(sessionPinningMiddleware);
3032
app.use(koiLogger.logger);
33+
app.use(manifestMiddleware);
3134

3235
app.get('/', statusRoute);
3336
app.get('/status', syncRoute);
@@ -36,6 +39,7 @@ export function start() {
3639

3740
graphServer({introspection: true, playground: true}).applyMiddleware({app, path: '/graphql'});
3841

42+
app.post('/tx', transactionRoute);
3943
app.get('/peers', peerRoute);
4044
app.get('/logs', koiLogsRoute);
4145
app.get('/logs/raw', koiLogsRawRoute);

src/database/sync.database.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export async function startSync() {
7777

7878
export async function parallelize(height: number) {
7979
clearTimeout(timer);
80-
timer = setTimeout(() => {
80+
timer = setTimeout(async () => {
8181
log.info('[database] sync timed out, restarting server');
8282
process.exit();
8383
}, 300 * 1000);
@@ -159,7 +159,7 @@ export async function storeBlock(height: number, retry: number = 0) {
159159
if (SIGKILL === false) {
160160
if (retry >= 25) {
161161
log.info(`[snapshot] there were problems retrieving ${height}, restarting the server`);
162-
process.exit();
162+
await startSync();
163163
} else {
164164
log.info(`[snapshot] could not retrieve block at height ${height}, retrying`);
165165
await storeBlock(height, retry + 1);

src/graphql/query.graphql.ts

+18-44
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {config} from 'dotenv';
22
import {QueryBuilder} from 'knex';
3-
import {indices} from '../utility/order.utility';
43
import {connection} from '../database/connection.database';
4+
import {indices} from '../utility/order.utility';
55
import {ISO8601DateTimeString} from '../utility/encoding.utility';
66
import {TagFilter} from './types';
77
import {tagToB64, toB64url} from '../query/transaction.query';
@@ -30,7 +30,7 @@ export interface QueryParams {
3030
offset?: number;
3131
select?: any;
3232
blocks?: boolean;
33-
since?: ISO8601DateTimeString;
33+
since?: ISO8601DateTimeString | string;
3434
sortOrder?: TxSortOrder;
3535
status?: 'any' | 'confirmed' | 'pending';
3636
pendingMinutes?: number;
@@ -41,7 +41,7 @@ export interface QueryParams {
4141
export async function generateQuery(params: QueryParams): Promise<QueryBuilder> {
4242
const {to, from, tags, id, ids, status = 'confirmed', select} = params;
4343
const {limit = 10, sortOrder = 'HEIGHT_DESC'} = params;
44-
const {since, offset = 0, minHeight = -1, maxHeight = -1} = params;
44+
const {since = new Date().toISOString(), offset = 0, minHeight = -1, maxHeight = -1} = params;
4545

4646
const query = connection
4747
.queryBuilder()
@@ -76,55 +76,29 @@ export async function generateQuery(params: QueryParams): Promise<QueryBuilder>
7676

7777
if (tags) {
7878
const tagsConverted = tagToB64(tags);
79-
const names: Array<string> = [];
80-
const values: Array<string> = [];
81-
82-
const subQuery = connection
83-
.queryBuilder()
84-
.select('*')
85-
.from('tags');
8679

87-
let runSubQuery = false;
88-
89-
for (let i = 0; i < tagsConverted.length; i++) {
90-
const tag = tagsConverted[i];
80+
tagsConverted.forEach((tag) => {
9181
let indexed = false;
9282

93-
for (let ii = 0; ii < indices.length; ii++) {
94-
const index = toB64url(indices[ii]);
83+
for (let i = 0; i < indices.length; i++) {
84+
const index = toB64url(indices[i]);
9585

9686
if (tag.name === index) {
87+
query.whereIn(`transactions.${indices[i]}`, tag.values);
9788
indexed = true;
98-
query.whereIn(`transactions.${index}`, tag.values);
9989
}
10090
}
10191

10292
if (indexed === false) {
103-
names.push(tag.name);
104-
values.push.apply(values, tag.values);
105-
106-
runSubQuery = true;
93+
query.whereIn('transactions.id', (subQuery) => {
94+
return subQuery
95+
.select('tx_id')
96+
.from('tags')
97+
.where('tags.name', tag.name)
98+
.whereIn('tags.value', tag.values);
99+
});
107100
}
108-
}
109-
110-
subQuery.whereIn('name', names);
111-
subQuery.whereIn('value', values);
112-
113-
if (runSubQuery) {
114-
const results = await subQuery
115-
.limit(limit)
116-
.offset(offset)
117-
.orderByRaw(tagOrderByClauses[sortOrder]);
118-
119-
const tx_ids = [];
120-
121-
for (let i = 0; i < results.length; i++) {
122-
const {tx_id} = results[i];
123-
tx_ids.push(tx_id);
124-
}
125-
126-
query.whereIn('transactions.id', tx_ids);
127-
}
101+
});
128102
}
129103

130104
if (minHeight >= 0) {
@@ -135,13 +109,13 @@ export async function generateQuery(params: QueryParams): Promise<QueryBuilder>
135109
query.where('transactions.height', '<=', maxHeight);
136110
}
137111

138-
query.limit(limit).offset(offset);
139-
140112
if (Object.keys(orderByClauses).includes(sortOrder)) {
141113
query.orderByRaw(orderByClauses[sortOrder]);
142114
}
143115

144-
query.orderByRaw('transactions.created_at DESC');
116+
query.limit(limit).offset(offset);
117+
118+
query.orderByRaw('transactions.id ASC');
145119

146120
return query;
147121
}

0 commit comments

Comments
 (0)