Skip to content

Commit

Permalink
Rename Pusher to Airnode feed (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
Siegrift authored Dec 11, 2023
1 parent f284527 commit 44fb407
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 37 deletions.
20 changes: 10 additions & 10 deletions local-test-configuration/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Local Airseeker test

The idea is to use the Docker images for Pusher, Signed API and Airseeker and run them locally. Specifically, this is
the setup:
The idea is to use the Docker images for Airnode feed, Signed API and Airseeker and run them locally. Specifically, this
is the setup:

- Use 2 pushers with Nodary API and reasonable fetch limits. Each pusher has a different Airnode mnemonic to mimic a
different API. One of the APIs is delayed so that the beacons have different values.
- Use 2 signed APIs and each Pusher pushes to a separate Signed API.
- Use 2 Airnode feeds with Nodary API and reasonable fetch limits. Each Airnode feed has a different Airnode mnemonic to
mimic a different API. One of the APIs is delayed so that the beacons have different values.
- Use 2 signed APIs and each Airnode feed pushes to a separate Signed API.
- We run Airseeker only on Hardhat network for setup simplicity. Initially, I wanted to have a Polygon testnet as well,
but gave up on that idea for now. The setup can be easily extended to run on any chain, just by not starting Hardhat
network and using a different RPCs.
Expand All @@ -19,7 +19,7 @@ assets from the Nodary API to see Airseeker updates.
missing secrets. Some of the secrets are the deployed contract addresses, which you'll get by following the next
instructions.

- Build all of the Docker containers. Do build containers for Pusher and Signed API you need to run
- Build all of the Docker containers. Do build containers for Airnode feed and Signed API you need to run
[this command](https://github.com/api3dao/signed-api/blob/0bad6fc8dd6aaffaa12cf099ab6bbf7c98d487c8/package.json#L11)
from the signed-api repository. For Airseeker, you can run `pnpm docker:build` from the root of this repository.

Expand All @@ -37,16 +37,16 @@ docker run --publish 4002:80 -it --init --volume $(pwd)/local-test-configuration

You can go to `http://localhost:4001/` and `http://localhost:4002/` to see the Signed API 1 and 2 respectively.

- Start Pusher 1 (in a separate terminal):
- Start Airnode feed 1 (in a separate terminal):

```sh
docker run -it --init --volume $(pwd)/local-test-configuration/pusher-1:/app/config --network host --env-file ./local-test-configuration/pusher-1/.env --rm --memory=256m api3/pusher:latest
docker run -it --init --volume $(pwd)/local-test-configuration/airnode-feed-1:/app/config --network host --env-file ./local-test-configuration/airnode-feed-1/.env --rm --memory=256m api3/airnode-feed:latest
```

- Start Pusher 2 (in a separate terminal):
- Start Airnode feed 2 (in a separate terminal):

```sh
docker run -it --init --volume $(pwd)/local-test-configuration/pusher-2:/app/config --network host --env-file ./local-test-configuration/pusher-2/.env --rm --memory=256m api3/pusher:latest
docker run -it --init --volume $(pwd)/local-test-configuration/airnode-feed-2:/app/config --network host --env-file ./local-test-configuration/airnode-feed-2/.env --rm --memory=256m api3/airnode-feed:latest
```

- Start Hardhat node (in a separate terminal):
Expand Down
58 changes: 31 additions & 27 deletions local-test-configuration/scripts/initialize-chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,23 @@ const joinUrl = (url: string, path: string) => {
return new URL(path, url).href;
};

const loadPusherConfig = (pusherDir: 'pusher-1' | 'pusher-2') => {
const configPath = join(__dirname, `/../`, pusherDir);
const rawConfig = JSON.parse(readFileSync(join(configPath, 'pusher.json'), 'utf8'));
const loadAirnodeFeedConfig = (airnodeFeedDir: 'airnode-feed-1' | 'airnode-feed-2') => {
const configPath = join(__dirname, `/../`, airnodeFeedDir);
const rawConfig = JSON.parse(readFileSync(join(configPath, 'airnode-feed.json'), 'utf8'));
const rawSecrets = dotenv.parse(readFileSync(join(configPath, 'secrets.env'), 'utf8'));

const secrets = parseSecrets(rawSecrets);
return interpolateSecrets(rawConfig, secrets);
};

const getBeaconSetNames = () => {
const pusher = loadPusherConfig('pusher-1');
const pusherWallet = ethers.Wallet.fromMnemonic(pusher.nodeSettings.airnodeWalletMnemonic);
const pusherBeacons = Object.values(pusher.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: pusherWallet.address });
const airnodeFeed = loadAirnodeFeedConfig('airnode-feed-1');
const airnodeFeedWallet = ethers.Wallet.fromMnemonic(airnodeFeed.nodeSettings.airnodeWalletMnemonic);
const airnodeFeedBeacons = Object.values(airnodeFeed.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: airnodeFeedWallet.address });
});

return pusherBeacons.map((beacon) => beacon.parameters[0]!.value);
return airnodeFeedBeacons.map((beacon) => beacon.parameters[0]!.value);
};

export const fundAirseekerSponsorWallet = async (funderWallet: ethers.Wallet) => {
Expand Down Expand Up @@ -210,28 +210,32 @@ export const deploy = async (funderWallet: ethers.Wallet, provider: ethers.provi
await tx.wait();

// Create templates
const pusher1 = loadPusherConfig('pusher-1');
const pusher2 = loadPusherConfig('pusher-2');
const pusher1Wallet = ethers.Wallet.fromMnemonic(pusher1.nodeSettings.airnodeWalletMnemonic).connect(provider);
const pusher2Wallet = ethers.Wallet.fromMnemonic(pusher2.nodeSettings.airnodeWalletMnemonic).connect(provider);
const pusher1Beacons = Object.values(pusher1.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: pusher1Wallet.address });
const airnodeFeed1 = loadAirnodeFeedConfig('airnode-feed-1');
const airnodeFeed2 = loadAirnodeFeedConfig('airnode-feed-2');
const airnodeFeed1Wallet = ethers.Wallet.fromMnemonic(airnodeFeed1.nodeSettings.airnodeWalletMnemonic).connect(
provider
);
const airnodeFeed2Wallet = ethers.Wallet.fromMnemonic(airnodeFeed2.nodeSettings.airnodeWalletMnemonic).connect(
provider
);
const airnodeFeed1Beacons = Object.values(airnodeFeed1.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: airnodeFeed1Wallet.address });
});
const pusher2Beacons = Object.values(pusher2.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: pusher2Wallet.address });
const airnodeFeed2Beacons = Object.values(airnodeFeed2.templates).map((template: any) => {
return deriveBeaconData({ ...template, airnodeAddress: airnodeFeed2Wallet.address });
});

// Derive beacon set IDs and names
const beaconSetIds = zip(pusher1Beacons, pusher2Beacons).map(([beacon1, beacon2]) =>
const beaconSetIds = zip(airnodeFeed1Beacons, airnodeFeed2Beacons).map(([beacon1, beacon2]) =>
ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [[beacon1!.beaconId, beacon2!.beaconId]]))
);
const beaconSetNames = pusher1Beacons.map((beacon) => beacon.parameters[0]!.value);
const beaconSetNames = airnodeFeed1Beacons.map((beacon) => beacon.parameters[0]!.value);

// Register merkle tree hashes
const timestamp = Math.floor(Date.now() / 1000);
const apiTreeValues = [
[pusher1Wallet.address, joinUrl(pusher1.signedApis[0].url, 'default')], // NOTE: Pusher pushes to the "/" of the signed API, but we need to query it additional path.
[pusher2Wallet.address, joinUrl(pusher2.signedApis[0].url, 'default')], // NOTE: Pusher pushes to the "/" of the signed API, but we need to query it additional path.
[airnodeFeed1Wallet.address, joinUrl(airnodeFeed1.signedApis[0].url, 'default')], // NOTE: Airnode feed pushes to the "/" of the signed API, but we need to query it additional path.
[airnodeFeed2Wallet.address, joinUrl(airnodeFeed2.signedApis[0].url, 'default')], // NOTE: Airnode feed pushes to the "/" of the signed API, but we need to query it additional path.
] as const;
const apiTree = StandardMerkleTree.of(apiTreeValues as any, ['address', 'string']);
const apiHashType = ethers.utils.solidityKeccak256(['string'], ['Signed API URL Merkle tree root']);
Expand Down Expand Up @@ -288,10 +292,10 @@ export const deploy = async (funderWallet: ethers.Wallet, provider: ethers.provi
.registerAirnodeSignedApiUrl(airnode, url, apiTreeRoot, apiTreeProof);
await tx.wait();
}
const dapiInfos = zip(pusher1Beacons, pusher2Beacons).map(([pusher1Beacon, pusher2Beacon], i) => {
const dapiInfos = zip(airnodeFeed1Beacons, airnodeFeed2Beacons).map(([airnodeFeed1Beacon, airnodeFeed2Beacon], i) => {
return {
airnodes: [pusher1Beacon!.airnodeAddress, pusher2Beacon!.airnodeAddress],
templateIds: [pusher1Beacon!.templateId, pusher1Beacon!.templateId],
airnodes: [airnodeFeed1Beacon!.airnodeAddress, airnodeFeed2Beacon!.airnodeAddress],
templateIds: [airnodeFeed1Beacon!.templateId, airnodeFeed1Beacon!.templateId],
dapiTreeValue: dapiTreeValues[i]!,
};
});
Expand Down Expand Up @@ -329,11 +333,11 @@ export const deploy = async (funderWallet: ethers.Wallet, provider: ethers.provi
api3ServerV1,
dapiDataRegistry,

pusher1Wallet,
pusher2Wallet,
airnodeFeed1Wallet,
airnodeFeed2Wallet,

pusher1Beacons,
pusher2Beacons,
airnodeFeed1Beacons,
airnodeFeed2Beacons,
beaconSetNames,
};
};
Expand Down

0 comments on commit 44fb407

Please sign in to comment.