Venti
Venti was developed in 2018 as an undergraduate thesis project aimed at addressing specific challenges within the Venezuelan financial landscape: severe cash scarcity, very slow POS systems and cumbersome bank transfer processes. It envisioned a peer-to-peer (P2P) payment system allowing users to send and receive money instantly via a simple Android application. A core requirement of the thesis was the integration of blockchain technology (blockchain was all the rage at the time) to ensure the integrity and immutability of transaction records.
This post offers a look into the technical architecture that powered it.
What and Why
As an academic project, Venti was mainly a proof of concept that didn’t require the usual
As usual with academic projects, building Venti involved limited timeframes and the need to fulfill specific objectives (like implementing a blockchain), while still aiming for a functional and user-friendly system. As a proof-of-concept, it didn’t dwell too much on things like scalability, though it did need to be something that could realistically grow into an actual product. The technology choices centered around:
- Rapid Development: Given the project timeline, technologies facilitating quick iteration were essential. Python and Django, known for their speed of development, were key choices.
- Ease of Deployment & Cost: Simplicity in deployment was important. PythonAnywhere was chosen as a hosting platform due to its ease of use for Python/Django applications and cost-effectiveness (i.e. it’s free) for a project of this scale.
- Fulfilling Core Requirements: The primary academic goal was to explore blockchain within a transactional system, while solving a real problem in Venezuela. This drove the design of a custom blockchain layer integrated directly into the backend logic and database.
- Mobile Platform: For the user interface, native Android development with Java was selected due to its wide reach in the target market (Venezuela) and the availability of mature development tools (Android Studio) and extensive documentation, crucial for developers relatively new to mobile app creation.
- Security Considerations: Handling user funds, even in a prototype, requires careful security measures. This included secure authentication, encryption of sensitive data (like credit card details before sending to the payment processor), and the inherent security features of the blockchain implementation.
This allowed Venti to meet its academic goals while delivering a working prototype demonstrating the core P2P payment functionality.
General Overview
Venti’s architecture consists of a native Android mobile application for user interaction, a backend API managing business logic and the blockchain, a relational database for persistence, and integration with an external payment gateway. The backend was hosted on PythonAnywhere.
graph TD subgraph PythonAnywhereHosting [PythonAnywhere Hosting] BackendAPI[Backend API Django/DRF + Blockchain Logic]; DB[(MySQL)]; WebServer[NGINX]; AppServer[uWSGI]; end User(User's Mobile Device) --> App[Android App Java]; App -- HTTPS REST API --> WebServer; WebServer --> AppServer; AppServer --> BackendAPI; BackendAPI --> DB; BackendAPI --> PaymentGateway[Instapago API]; BackendAPI --> EmailAPI[Gmail API for Password Reset]; style App fill:#D6EAF8,stroke:#333,stroke-width:2px,color:#333 style BackendAPI fill:#D5F5E3,stroke:#333,stroke-width:2px,color:#333 style DB fill:#FCF3CF,stroke:#333,stroke-width:2px,color:#333 style WebServer fill:#EAECEE,stroke:#333,stroke-width:1px,color:#333 style AppServer fill:#EAECEE,stroke:#333,stroke-width:1px,color:#333 style PaymentGateway fill:#EBDEF0,stroke:#333,stroke-width:2px,color:#333 style EmailAPI fill:#EBDEF0,stroke:#333,stroke-width:2px,color:#333
The system was designed to provide a seamless user experience for sending money, requesting funds, managing bank accounts/cards, and viewing transaction history, all underpinned by the security layer provided by the blockchain.
Frontend: The Mobile App (Android Native)
Users interacted with Venti through a dedicated Android application.
- Framework: Built natively for Android using the Android SDK.
- Language: Developed using Java.
- IDE: Android Studio was the primary development environment.
- API Interaction: Communicated with the backend via a REST API using Retrofit 2 and GSON for handling HTTP requests and JSON parsing. Glide was used for efficient image loading.
- Local Storage: Utilized Android’s
SharedPreferences
for storing user session tokens (from Knox), profile information, and encrypted credit card details (after initial encryption by the server). - UI/UX: Followed Material Design guidelines. Key screens included Login/Registration, Transaction History, Send/Request Money flows, Account/Card Management, and Profile Settings. Implemented
RecyclerView
for handling lists like transaction history. - Key Features: User authentication, profile creation/editing, adding bank accounts and credit cards (data encrypted before storage/use), sending/requesting funds, accepting/rejecting requests, viewing transaction history and account activity (recargas/canjeos), balance display.
The application aimed for intuitiveness, minimizing the steps required for common actions like sending money.
Backend: Django, DRF, and the Blockchain Core
Venti’s backend logic was built on a Python stack using Django and Django REST Framework (DRF).
- Core: Python 3.6, Django, and DRF.
- Structure: Organized as a single Django project (
venti
) containing the main application logic within a single app (ventiapp
). - API: Exposed RESTful endpoints using DRF’s
ViewSets
(for standard CRUD operations on models likeUser
,Profile
,BankAccount
) and customAPIView
classes (for specific actions likeCredito
,Canjeo
,MyProfile
,ResetPassword
). - Authentication: Employed
django-knox
for token-based authentication after login. A custom authentication class handled the initial username/password login. JWT was used for password reset token generation (RequestResetPassword
,ResetPassword
views). - Database Interaction: Primarily used the Django ORM for interacting with the MySQL (production) and SQLite (development) databases.
- Security:
- Credit card numbers and CVCs sent from the app were encrypted using Fernet symmetric encryption before being sent to the Instapago API (
Credito
view,EncriptarTarjeta
view). The Fernet key was stored server-side. Raw card details were not stored persistently on the server, only on the mobile app.
- Credit card numbers and CVCs sent from the app were encrypted using Fernet symmetric encryption before being sent to the Instapago API (
- Image Handling: Used
django-imagekit
to process uploaded profile images (resizing to 300x300 and converting to WEBP format) for optimization (Profile
model,helpers.py
). - External Integrations:
- Payments: Integrated with Instapago’s API using the
requests
library to process credit card top-ups (Credito
view). Bank withdrawals (Canjeo
view) generated transaction records and were intended to feed into a semi-manual batch file process for bank transfers1. - Email: Used the Google Gmail API via
google-api-python-client
andoauth2client
for sending password reset emails (helpers.py
,RequestResetPassword
view).
- Payments: Integrated with Instapago’s API using the
graph LR subgraph BackendCore [Backend Core on PythonAnywhere] DjangoApp[Django/DRF App w/ Blockchain Logic] end subgraph MiddlewareAndState [State & Dependencies] DB[(MySQL)] end subgraph ExternalServices [External Services] Instapago[Instapago API] GmailAPI[Google Gmail API] end %% Connections DjangoApp --> DB; DjangoApp --> Instapago; DjangoApp --> GmailAPI; %% Apply styles style DjangoApp fill:#D5F5E3,stroke:#333,stroke-width:2px,color:#333 style DB fill:#FCF3CF,stroke:#333,stroke-width:2px,color:#333 style Instapago fill:#EBDEF0,stroke:#333,stroke-width:2px,color:#333 style GmailAPI fill:#EBDEF0,stroke:#333,stroke-width:2px,color:#333
The Venti Blockchain Implementation
When the thesis project was initially proposed, the blockchain was a value add both from an academic (learning about a technology that was in vogue and growing) and from a product (increasing trust and “security”) perspective. As the project evolved, some of the characteristics of actual blockchains clashed with the problems the app was trying to solve. First of all, compute power was virtually non existent for this project, which meant that until a bigger community started mining, it would be trivially easy to perform a 51% attack. Second, part of the informal requirements for the project were for it to have a path to become an actual profitable venture, which was made more difficult if the core of the business revolved around a blockchain that wouldn’t be controlled by the company. Third and last, when trying to replace bank transfers, it would be a harder sale for users if all their transactions were public by default with what they would perceive as little gain. On the other hand, since a blockchain was already part of the approved proposal, the decision was made to implement what was called a “private” blockchain: a blockchain controlled by a single entity (thus losing the whole “decentralized” thing), but keeping some of the transparency it offers. This succeeded well on the academic goal of learning about blockchains, while still keeping some of the value add for the product with a proposed public verification mechanism.
- Purpose: To create an immutable, verifiable record of all transactions within the system, enhancing trust and security against tampering (both internal and external).
- Type: Private Blockchain. All logic for creating and managing the chain resided within the backend server code. There was no distributed consensus mechanism like Proof-of-Work or Proof-of-Stake.
- Structure & Integrity:
- Transaction Hashing: When a
Transaction
was successfully processed (e.g., funds moved between user balances), its core details (ID, sender, receiver, amount, message, timestamp) were serialized into a standardized JSON format. A SHA256 hash of this JSON string was computed and stored alongside the transaction record in theTransaction
database table (handled withinTransactionSerializer
). - Block Creation: Blocks were generated automatically by the system. After every 5 new transactions were recorded (checked within the
TransactionSerializer
’screate
method), the system triggered the creation of a newBlockchain
entry. - Linking & Signatures: The crucial element for immutability was the cryptographic linking. Each new
Blockchain
block stored:- References to the first and last
Transaction
IDs included in that block. - A precise timestamp of block creation.
- The RSA-2048 signature of the previous block’s hash (
prev_hash
). This signature was generated using a private RSA key (Secrets.PRIVATE_RSA_KEY
) kept only on the server. This acts as a “proof of identity” for the block creator (the Venti system itself). - The SHA256 hash of the current block’s entire contents (
this_hash
), which included its own metadata, the concatenation of all transaction hashes within its range, and the signed hash of the previous block. This was calculated by theBlockchainSerializer
.
- References to the first and last
- Immutability: Because each block contained a cryptographically signed reference to the previous one, modifying any past transaction or block would require re-calculating and re-signing all subsequent blocks. Without the private key, this is computationally infeasible, making the chain tamper-evident.
- Genesis Block: A special procedure within the
TransaccionInicialSerializer
handled the creation of the first transaction (a system-internal initialization) and the first block, using a predefined value (“Bloque Inicial”) for theprev_hash
field.
- Transaction Hashing: When a
- Storage: Both individual transaction hashes (
Transaction.hash
) and the block metadata (Blockchain
model instance) were stored directly in the primary MySQL database. - Verification (Conceptual): The thesis proposed that external verification could be possible without revealing sensitive transaction details. An auditor (or even a user verifying their own history) could:
- Recalculate the SHA256 hash of a specific transaction’s details.
- Verify this matches the
hash
stored with theTransaction
record. - Obtain the
Blockchain
block data (containing timestamps, transaction ranges,this_hash
, and the signedprev_hash
). - Using the publicly available Venti public RSA key, verify the signature (
prev_hash
) against thethis_hash
of the preceding block. - Concatenate all transaction hashes within the block’s range, combine with block metadata and the verified (decrypted) previous hash, and re-calculate the SHA256 hash of the current block to ensure it matches the stored
this_hash
. This process could confirm the integrity of the chain and the inclusion of specific transactions without exposing sender/receiver details publicly.
graph TD subgraph BlockchainProcess [Blockchain Generation Flow] NewTx[New Transaction Saved] --> HashTx[Calculate Tx Hash SHA256]; HashTx --> StoreTxHash[Store Hash in Transaction Table]; StoreTxHash --> CheckCount{Tx Count >= 5?}; CheckCount -- Yes --> SignPrevHash[Sign Previous Block Hash with Private RSA Key]; SignPrevHash --> CreateBlock[Create New Block Metadata - Tx Range, Timestamp, Signed Prev Hash]; CreateBlock --> AggregateTxHashes[Aggregate Hashes of Txs in Block]; AggregateTxHashes --> HashBlock[Calculate Current Block Hash SHA256 - Metadata + Tx Hashes + Signed Prev Hash]; HashBlock --> StoreBlock[Store Block Metadata + Block Hash in Blockchain Table]; CheckCount -- No --> End; end style NewTx fill:#D5F5E3,stroke:#333,stroke-width:2px,color:#333 style CheckCount fill:#FFF3CD,stroke:#333,stroke-width:2px,color:#333 style SignPrevHash fill:#D6EAF8,stroke:#333,stroke-width:2px,color:#333 style HashBlock fill:#D6EAF8,stroke:#333,stroke-width:2px,color:#333 style StoreTxHash fill:#FCF3CF,stroke:#333,stroke-width:2px,color:#333 style StoreBlock fill:#FCF3CF,stroke:#333,stroke-width:2px,color:#333
This custom implementation provided the required blockchain features for the thesis, focusing on data integrity through hashing and asymmetric cryptography signatures within a centralized system architecture.
Database: MySQL & SQLite
The primary data store for production was MySQL, hosted on PythonAnywhere. SQLite was used for local development.
- Type: Relational database.
- Management: Database schema defined using Django models (
User
,Profile
,Email
,PhoneNumber
,BankAccount
,Transaction
,Request
,Blockchain
). Schema changes managed via Django migrations. - Interaction: Accessed exclusively through the Django ORM.
- Key Models: Stored user details, balances, contact info, bank accounts, individual transactions (with their hashes), payment requests, and the blockchain metadata itself.
- Operations: Ran as a single instance managed by PythonAnywhere. The thesis notes the process for generating withdrawal batch files but doesn’t detail automated database backups beyond standard Django operations.
Infrastructure & Hosting: PythonAnywhere
The Venti backend was hosted entirely on PythonAnywhere, a Platform-as-a-Service (PaaS) environment simplifying Python web application deployment.
- Platform: PythonAnywhere (running on AWS EC2 infrastructure).
- Web Server: NGINX, configured by PythonAnywhere, served static files (like profile images processed by ImageKit) and proxied dynamic requests. It also handled HTTPS redirection.
- Application Server: uWSGI, communicating with NGINX and running the Django application code within a Python virtual environment.
- Deployment: Updates were typically done manually by pulling the latest code from a Git repository (like GitHub) via the PythonAnywhere console and reloading the web application. No containerization (like Docker) was used.
- Environment: Utilized Python virtual environments to manage dependencies separate from the system Python installation.
graph TD subgraph PythonAnywhereInstance [PythonAnywhere Hosted Environment] direction LR NGINX[NGINX Web Server] --> uWSGI[uWSGI App Server]; uWSGI --> DjangoApp[Django/DRF Application]; DjangoApp --> PythonVenv[Python Virtual Env]; DjangoApp --> MySQLDB[(MySQL Database)]; NGINX -- Serves --> StaticFiles[Static Files /media/]; end style PythonAnywhereInstance stroke-width:2px style NGINX fill:#EAECEE,stroke:#333,stroke-width:1px,color:#333 style uWSGI fill:#EAECEE,stroke:#333,stroke-width:1px,color:#333 style DjangoApp fill:#D5F5E3,stroke:#333,stroke-width:1px,color:#333 style PythonVenv fill:#FDF2E9,stroke:#333,stroke-width:1px,color:#333 style MySQLDB fill:#FCF3CF,stroke:#333,stroke-width:1px,color:#333 style StaticFiles fill:#FDEBD0,stroke:#333,stroke-width:1px,color:#333
This setup provided a straightforward way to get the Django application running online without managing server infrastructure directly.
Networking & Edge: Simple HTTPS
Networking was relatively simple, relying on PythonAnywhere’s infrastructure.
- Traffic Flow: User requests from the Android app connected over the internet via HTTPS to PythonAnywhere’s load balancers (implicitly), which routed traffic to the NGINX server configured for the Venti application. NGINX then passed the request to uWSGI and the Django application.
- Security: HTTPS was enforced by configuring NGINX (via PythonAnywhere’s interface) to redirect HTTP traffic. SSL certificates were automatically managed by PythonAnywhere for
*.pythonanywhere.com
subdomains. No additional CDN or WAF was employed. - Performance: Relied on the basic performance of PythonAnywhere’s hosting tiers and the efficiency of the Django application itself. Image optimization via ImageKit helped reduce load times for profile pictures.
sequenceDiagram participant User participant PAEdge as PythonAnywhere Edge/LB participant NGINXCont as NGINX @PythonAnywhere participant uWSGICont as uWSGI @PythonAnywhere participant DjangoCont as Django App @PythonAnywhere User->>PAEdge: HTTPS Request venti.pythonanywhere.com PAEdge->>NGINXCont: Forward Request NGINXCont->>uWSGICont: Forward to App Server uWSGICont->>DjangoCont: Execute Django View DjangoCont-->>uWSGICont: Response uWSGICont-->>NGINXCont: Response NGINXCont-->>PAEdge: Response PAEdge-->>User: HTTPS Response
Parting thoughts
Venti successfully met its primary goal as an undergraduate thesis: demonstrating the feasibility of a P2P payment application incorporating blockchain technology within the Venezuelan context. The use of Django and DRF allowed for rapid development of the core API, while native Android provided the user interface. The custom blockchain implementation, while perhaps not production-ready in terms of performance or standard practices compared to established public chains, fulfilled the academic requirement and provided a functional layer of transaction immutability secured by RSA signatures.
The project highlighted the potential for such systems while also underscoring the real-world challenges, particularly around seamless integration with the existing banking infrastructure in a complex regulatory environment1. It stands as an interesting case study in applying blockchain concepts to a specific regional problem, built with practical, accessible technologies.