I am using here the description and terminology from RFC 7539.
ChaCha20 is meant to process messages, each message being a sequence of bytes; ChaCha20 produces pseudo-random blocks of 64 bytes each, which are XORed with the data to encrypt or decrypt. The crucial security property is that all invocations of the ChaCha20 block function for a given key use distinct values for what is injected in state words 12 to 15.
In the description of RFC 7539, state word 12 receives a counter value, which is over 32 bits and incremented for each block, while state words 13 to 15 receive a 96-bit "nonce" which is fixed for a given message, but different for each message. The idea is that, for a given key:
- Each message works over a new nonce value (96 bits), such that no two messages share the same nonce.
- Within a message, different blocks use the same nonce, but a different counter values.
- No message may contain more than $2^{32}$ blocks (i.e. close to 275 gigabytes, which "ought to be enough").
Nonce values themselves can be generated in any way that offers the unicity guarantee with sufficient probability. If you generate nonce values randomly (with a uniform generator), then the risk of reuse is low as long as you do not produce too many messages; with $n$ messages, probability of reuse is about $n^2/2^{96}$. In other words, if you do not send more than 8 billion messages with random 96-bit nonces and the same key, then the risk of reusing the same nonce is less than one in a billion.
Take care that all of the above is for reusing a nonce value with the same key. If two messages use the same nonce+counter but with different keys, then there is no security issue.
In a P2P network, conceptually, messages are encrypted with keys derived from some sort of key exchange (e.g. ECDH), and each node must remember the key to use for each of its neighbors; it should not be too much a hassle to remember a counter value along with each such key, in particular if these keys are ephemeral, i.e. only in RAM.