-
Notifications
You must be signed in to change notification settings - Fork 108
Content Node: Architecture
An Audius Content Node maintains the availability of creators' content on IPFS. The information stored includes Audius user metadata, images, and audio content.
NOTE - Previously, there was a concept of a ”creator node” that was separate from a content node. These have been combined into a single node type rather than being separate, with ”content node” referring to the merged type. Some references to ”creator node” still exist in Audius code and in other documentation; those can safely be assumed to be referring to the content nodes outlined here.
The content node is written in NodeJS. The node uses FFMPEG to process & segment tracks.
Web Server
The content node's core service is a web server with an HTTP API to process incoming requests and perform the following functions:
- user & track metadata upload
- user & track image upload
- user track file upload
- user & track associations with ETH contract values
- All users and tracks are tied to Ethereum wallet addresses and unique IDs
- user & track data, metadata, and file retrieval
The web server is an Express app.
IPFS Node
A content node runs a dedicated IPFS node to provide decentralized availability of all Audius creator content. The web server interacts with an IPFS node through the JS IPFS API
Persistent Storage (Postgres)
It stores all data in a SQL database and all images and metadata objects on its IPFS node. Each track is stored twice, once in persistent storage and second on a dedicated IPFS node, which is treated as ephemeral.
Pointers to all content and metadata stored in IPFS are persisted in the Postgres DB.
Postgres is managed in the codebase using the Sequelize ORM which includes migrations, models and validations
Redis
A Redis client is used for for resource locking, request rate limiting, and limited caching and key storage.
Redis is managed in the codebase through the ioredis npm package
Track Segmenting
As defined by the Audius protocol, the content node segments all uploaded track files before storing/serving.
Data Redundancy
As defined by the Audius protocol, all creators are encouraged to store content redundantly across multiple nodes to maximize availability. Each node thus exposes sync functionality that a creator can use to transfer their metadata and files to another node. Metadata is transferred directly and files are transferred directly through the peer IPFS nodes.
Persistent storage can be cloud-backed (e.g. S3) or a local volume / directory.
CNodeUser
A CNodeUser object represents a content node user, created for each Ethereum owner wallet address. All other data models are associated with a wallet indirectly through a CNodeUser.
AudiusUser
An AudiusUser object represents an Audius user on the Ethereum blockchain. It references Tracks for all track entries, references Files for coverArt, profilePic, and user metadata object, and redundantly holds the user metadata JSON object. Each AudiusUser is owned by a CNodeUser.
Track
A Track object represents an Audius track on the Ethereum blockchain. It references Files for coverArt and track metadata object, and redundantly holds the track metadata JSON object. Each Track is owned by an AudiusUser.
File
A File object holds the CID of the file pinned by the IPFS node, the name of the uploaded source file, and the file's storage path in the content node's persistent storage. Each File is owned by a Track or AudiusUser.
SessionToken
A SessionToken object allows content node clients permissioned access to their own data on that node, and blocks access to other CNodeUser's data. Each SessionToken is owned by a CNodeUser.
All content node objects are identified with UUIDs to account for the distributed nature of this data, allowing safe data transfer between nodes.
CNodeUser
-
POST /users
Authorize a new CNodeUser to use the content node, and enable all other data creation.
-
[DEPRECATED] POST /users/login
Given wallet address and valid signature for key associated with wallet, and creates session for future interaction with node.
-
GET /users/login/challenge
Given the public wallet key, returns a challenge for validating user login and sets the challenge in Redis cache
-
POST /users/login/challenge
Checks if challenge in request body matches up with what we have stored. If request challenge matches what we have, remove instance from Redis to prevent replay attacks. Return sessionToken upon success.
-
POST /users/logout
Given token, deletes node session for wallet.
AudiusUser
-
POST /audius_users/metadata
Create AudiusUser from provided metadata, and make metadata available to network.
-
POST /audius_users/associate/{audiusUserUUID}
Given audiusUser blockchainUserId, blockNumber, and metadataFileUUID, creates/updates AudiusUser DB entry and associates image file entries with audiusUser. Ends audiusUser creation/update process.
Track
-
POST /track_content
Given uploaded track file, segments it into multiple files, stores each file in persistent storage, adds to IPFS node, and creates DB File entry. Track will be associated as Audius Track in POST /tracks route.
-
POST /tracks/metadata
Given track metadata object, upload and share metadata to IPFS. Return metadata multihash if successful. Error if associated track segments have not already been created and stored.
-
POST /tracks
Given track blockchainTrackId, blockNumber, and metadataFileUUID, creates/updates Track DB track entry and associates segment & image file entries with track. Ends track creation/update process.
-
GET /tracks/download_status/{blockchainId}
Returns download status of track and 320kbps CID if ready + downloadable.
-
GET /tracks/stream/:encodedId
Gets a streamable mp3 link for a track by encodedId. Supports range request headers.
-
GET /tracks/unlisted
List all unlisted tracks for a user
File
-
POST /image_upload
Given image file, save multiple-resolutions in persistent storage and to IPFS, then create DB File entries.
-
GET /ipfs_peer_info
Returns data pertaining to IPFS client
-
GET /ipfs/{CID}
Given IPFS CID, returns file stream if stored on node via file system. If not available on file system, get and stream content from IPFS.
-
GET /ipfs/{dirCID}/{filename}
Gets a CID in a directory, streaming from the filesystem if available and falling back to IPFS if not. The filename is one of the multi-resolution images served.
NodeSync
-
GET /export
Given wallet array, returns all DB data including CNodeUser, AudiusUsers, Tracks, Files. Also rehydrates all files in IPFS nodes per cnode UUID if the files associated with that cnode UUID has not been rehydrated in the past hour.
-
POST /sync
Given wallet array and target content node endpoint, fetches data export from endpoint for wallets, then stores all fetched data in DB. Peers to other node's IPFS node and stores in persistent storage.
-
GET /sync_status/{walletPublicKey}
Checks if node sync is in progress for a wallet
HealthCheck
-
GET /health_check
Returns 200 with info pertaining to the current version, current service, selected Discovery Node, and if the web server and the db connection are both up
-
GET /version
Returns content node version data required for Audius protocol participation.
-
GET /health_check/ipfs
Performs diagnostic ipfs operations to confirm functionality
-
GET /db_check
Exposes current and max db connection stats. Returns error if db connection threshold exceeded, else success.
-
GET /disk_check
Exposes current and max disk usage stats. Returns error if max disk usage exceeded, else success.
Track Creation Flow
- POST /track_content Client uploads track file to content node
- Receives back segment multihash array as proof of storage / availability
- Client packages returned multihash array into track metadata object
- POST /tracks Client uploads track metadata object to content node
- Receives back metadata multihash as proof of storage / availability
- Client uploads track metadata object to Audius blockchain
- Receives back blockchain track ID as proof of record
- [POST /tracks/associate/:id] Client uploads blockchain track ID to content node to prove blockchain upload of track
- Content node associates blockchain track ID with previously created track
- this completes track creation process
Track Update Flow
- Client posts any image files to [POST /image_upload] if image was changed and updates multihash in metadata object
- [POST /metadata] Client uploads the new metadata to content node and retrieves multihash
- Client updates multihash on chain for track
- Receives the transaction receipt to confirm success transaction
- [PUT /track/:id] Client put's the metadata to the track update endpoint, which will update the content node db and make any associated changes now to mirror the blockchain
- Home
- Start Here
- Content-Node
- Discovery Node
- Ethereum Smart Contracts
- Slashing
- Identity Service