From b9aebfddf713b3689800acc5327099a52f7f12bb Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Wed, 28 Jul 2021 12:43:02 -0700 Subject: [PATCH] Implemented /txinfo/ethereum_blockchain This is an authentiated endpoint which currently returns decoded ABI information from input bytecode in an Ethereum transaction. In the future, we should add all transaction display enrichment code to this endpoint (for Ethereum blockchain transactions). --- backend/moonstream/api.py | 2 + backend/moonstream/data.py | 21 +++++ backend/moonstream/routes/txinfo.py | 80 +++++++++++++++++++ .../scripts/txinfo_ethereum_blockchain.bash | 52 ++++++++++++ .../txinfo_ethereum_blockchain_request.json | 11 +++ 5 files changed, 166 insertions(+) create mode 100644 backend/moonstream/routes/txinfo.py create mode 100755 backend/scripts/txinfo_ethereum_blockchain.bash create mode 100644 backend/scripts/txinfo_ethereum_blockchain_request.json diff --git a/backend/moonstream/api.py b/backend/moonstream/api.py index 9160b086..412e3834 100644 --- a/backend/moonstream/api.py +++ b/backend/moonstream/api.py @@ -9,6 +9,7 @@ from fastapi.middleware.cors import CORSMiddleware from . import data from .routes.subscriptions import app as subscriptions_api from .routes.users import app as users_api +from .routes.txinfo import app as txinfo_api from .settings import ORIGINS from .version import MOONSTREAM_VERSION @@ -38,3 +39,4 @@ async def version_handler() -> data.VersionResponse: app.mount("/subscriptions", subscriptions_api) app.mount("/users", users_api) +app.mount("/txinfo", txinfo_api) diff --git a/backend/moonstream/data.py b/backend/moonstream/data.py index 01944f84..f11f338c 100644 --- a/backend/moonstream/data.py +++ b/backend/moonstream/data.py @@ -88,3 +88,24 @@ class EVMEventSignature(BaseModel): class ContractABI(BaseModel): functions: List[EVMFunctionSignature] events: List[EVMEventSignature] + + +class EthereumTransaction(BaseModel): + gas: int + gasPrice: int + value: int + from_address: str = Field(alias="from") + to_address: Optional[str] = Field(default=None, alias="to") + hash: Optional[str] = None + input: Optional[str] = None + + +class TxinfoEthereumBlockchainRequest(BaseModel): + tx: EthereumTransaction + + +class TxinfoEthereumBlockchainResponse(BaseModel): + tx: EthereumTransaction + abi: Optional[ContractABI] = None + errors: List[str] = Field(default_factory=list) + diff --git a/backend/moonstream/routes/txinfo.py b/backend/moonstream/routes/txinfo.py new file mode 100644 index 00000000..033ce902 --- /dev/null +++ b/backend/moonstream/routes/txinfo.py @@ -0,0 +1,80 @@ +""" +Moonstream's /txinfo endpoints. + +These endpoints enrich raw blockchain transactions (as well as pending transactions, hypothetical +transactions, etc.) with side information and return objects that are better suited for displaying to +end users. +""" +import logging +from typing import Any, Dict + +from fastapi import ( + FastAPI, + Depends, + HTTPException, + Request, +) +from fastapi.middleware.cors import CORSMiddleware +from moonstreamdb.db import yield_db_session +from sqlalchemy.orm import Session + +from ..abi_decoder import decode_abi +from ..data import TxinfoEthereumBlockchainRequest, TxinfoEthereumBlockchainResponse +from ..middleware import BroodAuthMiddleware +from ..settings import ( + MOONSTREAM_APPLICATION_ID, + DOCS_TARGET_PATH, + ORIGINS, + DOCS_PATHS, + bugout_client as bc, +) +from ..version import MOONSTREAM_VERSION + +logger = logging.getLogger(__name__) + +tags_metadata = [ + {"name": "users", "description": "Operations with users."}, + {"name": "tokens", "description": "Operations with user tokens."}, +] + +app = FastAPI( + title=f"Moonstream users API.", + description="User, token and password handlers.", + version=MOONSTREAM_VERSION, + openapi_tags=tags_metadata, + openapi_url="/openapi.json", + docs_url=None, + redoc_url=f"/{DOCS_TARGET_PATH}", +) + +app.add_middleware( + CORSMiddleware, + allow_origins=ORIGINS, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +whitelist_paths: Dict[str, str] = {} +whitelist_paths.update(DOCS_PATHS) +app.add_middleware(BroodAuthMiddleware, whitelist=whitelist_paths) + + +@app.post( + "/ethereum_blockchain", + tags=["txinfo"], + response_model=TxinfoEthereumBlockchainResponse, +) +async def txinfo_ethereum_blockchain_handler( + txinfo_request: TxinfoEthereumBlockchainRequest, + db_session: Session = Depends(yield_db_session), +) -> TxinfoEthereumBlockchainResponse: + response = TxinfoEthereumBlockchainResponse(tx=txinfo_request.tx) + if txinfo_request.tx.input is not None: + try: + response.abi = decode_abi(txinfo_request.tx.input, db_session) + except Exception as err: + logger.error(r"Could not decode ABI:") + logger.error(err) + response.errors.append("Could not decode ABI from the given input") + return response diff --git a/backend/scripts/txinfo_ethereum_blockchain.bash b/backend/scripts/txinfo_ethereum_blockchain.bash new file mode 100755 index 00000000..8a274a5f --- /dev/null +++ b/backend/scripts/txinfo_ethereum_blockchain.bash @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +TIMESTAMP="$(date +%s)" +SCRIPT_DIR=$(realpath $(dirname $0)) + +API_URL="${MOONSTREAM_DEV_API_URL:-http://localhost:7481}" + +MOONSTREAM_USERNAME="devuser_$TIMESTAMP" +MOONSTREAM_PASSWORD="peppercat" +MOONSTREAM_EMAIL="devuser_$TIMESTAMP@example.com" + +OUTPUT_DIR=$(mktemp -d) +echo "Writing responses to directory: $OUTPUT_DIR" + +# Create a new user +curl -X POST \ + -H "Content-Type: multipart/form-data" \ + "$API_URL/users/" \ + -F "username=$MOONSTREAM_USERNAME" \ + -F "password=$MOONSTREAM_PASSWORD" \ + -F "email=$MOONSTREAM_EMAIL" \ + -o $OUTPUT_DIR/user.json + +# Create a token for this user +curl -X POST \ + -H "Content-Type: multipart/form-data" \ + "$API_URL/users/token" \ + -F "username=$MOONSTREAM_USERNAME" \ + -F "password=$MOONSTREAM_PASSWORD" \ + -o $OUTPUT_DIR/token.json + +API_TOKEN=$(jq -r '.id' $OUTPUT_DIR/token.json) + +set -e + +ETHEREUM_TXINFO_REQUEST_BODY_JSON=$(jq -r . $SCRIPT_DIR/txinfo_ethereum_blockchain_request.json) +curl -f -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $API_TOKEN" \ + "$API_URL/txinfo/ethereum_blockchain" \ + -d "$ETHEREUM_TXINFO_REQUEST_BODY_JSON" \ + -o $OUTPUT_DIR/txinfo_response.json + +echo "Response:" +jq . $OUTPUT_DIR/txinfo_response.json + +if [ "$DEBUG" != true ] +then + echo "Deleting output directory: $OUTPUT_DIR" + echo "Please set DEBUG=true if you would prefer to retain this directory in the future" + rm -r $OUTPUT_DIR +fi \ No newline at end of file diff --git a/backend/scripts/txinfo_ethereum_blockchain_request.json b/backend/scripts/txinfo_ethereum_blockchain_request.json new file mode 100644 index 00000000..1a78035e --- /dev/null +++ b/backend/scripts/txinfo_ethereum_blockchain_request.json @@ -0,0 +1,11 @@ +{ + "tx": { + "to": null, + "from": "0x2E337E0Fb68F5e51ce9295E80BCd02273d7420c4", + "gas": 2265656, + "gasPrice": 1000000000, + "hash": "0x5f0b6e212e55c7120f36fe6f88d46eb001c848064fd099116b42805bb3564ae6", + "value": 0, + "input": "0x606061026b61014039602061026b60c03960c05160a01c1561002057600080fd5b61014051600055610160516001556001546101805181818301101561004457600080fd5b80820190509050600255600254421061005c57600080fd5b61025356600436101561000d576101ec565b600035601c52600051631998aeef8114156100855760015442101561003157600080fd5b600254421061003f57600080fd5b600454341161004d57600080fd5b600660035460e05260c052604060c020805460045481818301101561007157600080fd5b808201905090508155503360035534600455005b341561009057600080fd5b633ccfd60b8114156100db5760063360e05260c052604060c0205461014052600060063360e05260c052604060c02055600060006000600061014051336000f16100d957600080fd5b005b63fe67a54b811415610124576002544210156100f657600080fd5b6005541561010357600080fd5b600160055560006000600060006004546000546000f161012257600080fd5b005b6338af3eed81141561013c5760005460005260206000f35b634f245ef78114156101545760015460005260206000f35b632a24f46c81141561016c5760025460005260206000f35b6391f901578114156101845760035460005260206000f35b63d57bde7981141561019c5760045460005260206000f35b6312fa6feb8114156101b45760055460005260206000f35b6326b387bb8114156101ea5760043560a01c156101d057600080fd5b600660043560e05260c052604060c0205460005260206000f35b505b60006000fd5b61006161025303610061600039610061610253036000f30000000000000000000000002e337e0fb68f5e51ce9295e80bcd02273d7420c40000000000000000000000000000000000000000000000000000000060d2b04a00000000000000000000000000000000000000000000000000000000616b46ca" + } +}