Search code examples
node.jsdockergetsmartcontractsweb3js

Sending a GET method request to a node server running on Docker


I'm currently running a node server using Docker that will interact with a smart contract already uploaded. Here is my Docker file:

FROM node:7
WORKDIR /app
COPY package.json /app
RUN npm install
RUN npm install -g npm
RUN ls
COPY . /app
CMD node gameserver.js
EXPOSE 8081
ARG walletPrivate
ENV walletPrivate = $private
ARG walletPublic
ENV walletPublic = $public

I am defining variables that I will pass in on runtime. Here is the server code:

const express = require('express');
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const MissionTrackerJson = require('./contracts/MissionTracker.json');

const app = express();
const port = process.env.PORT || 5001;
const providerUrl = 'https://rinkeby.infura.io/N9Txfkh1TNZhoeKXV6Xm';

const gamePublicKey = process.env.public;
const gamePrivateKey = process.env.private;
const production = true;

let contractAddress = null;
let contract = null;

let web3 = new Web3(new Web3.providers.HttpProvider(providerUrl));
if (typeof web3 === 'undefined') throw 'No web3 detected. Is Metamask/Mist being used?';
console.log("Using web3 version: " + Web3.version);

let contractDataPromise = MissionTrackerJson;
let networkIdPromise = web3.eth.net.getId(); // resolves on the current network id

Promise.all([contractDataPromise, networkIdPromise])
.then(results => {
    let contractData = results[0];
    let networkId = results[1];

    // Make sure the contract is deployed on the connected network
    if (!(networkId in contractData.networks)) {
        throw new Error("Contract not found in selected Ethereum network on MetaMask.");
    }

    contractAddress = contractData.networks[networkId].address;
    contract = new web3.eth.Contract(contractData.abi, contractAddress);
    app.listen(port, () => console.log(`Site server on port ${port}`));
})
.catch(console.error);

if (production) {
    app.use('/', express.static(`${__dirname}/client/build`));
}

app.get('/api/complete_checkpoint/:reviewer/:checkpoint', (req, res) => {
    let reviewerId = req.params.reviewer;
    let checkpointId = req.params.checkpoint;
    let encodedABI = contract.methods.setCheckpointComplete(reviewerId, checkpointId).encodeABI();

    web3.eth.getTransactionCount(gamePublicKey, 'pending')
    .then(nonce => {
        let rawTx = {
            from: gamePublicKey,
            to: contractAddress,
            gas: 2000000,
            data: encodedABI,
            gasPrice: '100',
            nonce,
        };

        let tx = new Tx(rawTx);
        tx.sign(gamePrivateKey);
    
        let serializedTx = tx.serialize();
    
        web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'))
        .on('receipt', console.log)
        .catch(console.error);
    })
});

app.get('/api/add_checkpoint/:checkpoint_name', (req, res) => {
    console.log("hello");
    let checkpointName = decodeURIComponent(req.params.checkpoint_name);
    let encodedABI = contract.methods.addGameCheckpoint(checkpointName).encodeABI();

    web3.eth.getTransactionCount(gamePublicKey, 'pending')
    .then(nonce => {
        let rawTx = {
            from: gamePublicKey,
            to: contractAddress,
            gas: 2000000,
            data: encodedABI,
            gasPrice: '100',
            nonce,
        };

        let tx = new Tx(rawTx);
        tx.sign(gamePrivateKey);
    
        let serializedTx = tx.serialize();
    
        web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'))
        .on('receipt', console.log)
        .catch(console.error);
    })
});
console.log("end");

To call the contract, I need to ping the server with an HTTP GET method. I have figured out that the IP address of my Docker server is 172.17.0.2:8081 when I run the following command:

docker run -t -i --env private=0x12345 --env public=0x11111 -p 8081:8081 game_server

I am making my outward port 8081

How can I send an HTTP GET method to my server? Is there some other address I should be looking for?


Solution

  • I think things are a bit messy in your Dockerfile:

        FROM node:7
        WORKDIR /app
        COPY package.json /app <== this is copying package.json to 
        /app/app...should just be COPY package.json .
        RUN npm install
        RUN npm install -g npm <== unnecessary as npm bundles with node
        RUN ls <== unnecessary
        COPY . /app <== again, you're copying to /app/app
        CMD node gameserver.js <== this should go as the last line
        EXPOSE 8081 <== this should be the second to last line
        ARG walletPrivate
        ENV walletPrivate = $private
        ARG walletPublic
        ENV walletPublic = $public
    

    When you run your container, are you seeing that it's actually working? Since you have that /app/app thing going on, I'd be surprised if the CMD node gameserver.js command actually found your server file.

    Also, your gameserver.js file expects a PORT environment variable that you're not supplying. Since it's not being supplied, your node server is listening on port 5001, not 8081...therefore, exposing 8081 isn't going to help you. Instead of exposing 8081 from the container, add -p "8081:5001" to your run command. Or, supply 8081 as an environment variable.