Bitcoin Forum
September 09, 2025, 08:36:04 AM *
News: Latest Bitcoin Core release: 29.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: "Amount in satoshis can be negative", How true ?  (Read 273 times)
Felicity_Tide (OP)
Sr. Member
****
Offline Offline

Activity: 518
Merit: 313


cout << "Bitcoin";


View Profile
November 09, 2024, 05:44:30 AM
Merited by pooya87 (2), ABCbits (2), garlonicon (1)
 #1

While checking for new articles that i might've not have come across, i saw a topic that says "How many satoshis are in a bitcoin". This is a question i could possibly answer while sleeping, but i haven't really done a research on why Bitcoin has to be measured in sats.

I did a quick research on the source code, and surprisingly, i got a very short code that is not more than 30 lines (if you add the comments). I had to snipped out some part because the confusion is actually from these two lines.

Code:
~snip

/** Amount in satoshis (Can be negative) */
typedef int64_t CAmount;

~snip

static constexpr CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
https://github.com/bitcoin/bitcoin/blob/master/src/consensus/amount.h#L1

I want to believe that the first line of code represents the amount of Bitcoin in it's smallest unit (sats), as stated in the comment, and there was an additional statement that insists that it can be negative.

Now, if you take a look at the next line of code, there is a true or false case (boolean). If the nValue is above zero and below the MAX, the function returns True, but if reverse is the case, then it should return False.

So my question here is:
1. How can the amount in satoshi be negative when any nValue aside the True condition must return false?



I am 100% open to correction as I still see myself as a learner. Pardon any of my error and share your personal opinion. You might want to also DYOR after reading this.

R


▀▀▀▀▀▀▀██████▄▄
████████████████
▀▀▀▀█████▀▀▀█████
████████▌███▐████
▄▄▄▄█████▄▄▄█████
████████████████
▄▄▄▄▄▄▄██████▀▀
LLBIT|
4,000+ GAMES
███████████████████
██████████▀▄▀▀▀████
████████▀▄▀██░░░███
██████▀▄███▄▀█▄▄▄██
███▀▀▀▀▀▀█▀▀▀▀▀▀███
██░░░░░░░░█░░░░░░██
██▄░░░░░░░█░░░░░▄██
███▄░░░░▄█▄▄▄▄▄████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
█████████
▀████████
░░▀██████
░░░░▀████
░░░░░░███
▄░░░░░███
▀█▄▄▄████
░░▀▀█████
▀▀▀▀▀▀▀▀▀
█████████
░░░▀▀████
██▄▄▀░███
█░░█▄░░██
░████▀▀██
█░░█▀░░██
██▀▀▄░███
░░░▄▄████
▀▀▀▀▀▀▀▀▀
|||
▄▄████▄▄
▀█▀
▄▀▀▄▀█▀
▄░░▄█░██░█▄░░▄
█░▄█░▀█▄▄█▀░█▄░█
▀▄░███▄▄▄▄███░▄▀
▀▀█░░░▄▄▄▄░░░█▀▀
░░██████░░█
█░░░░▀▀░░░░█
▀▄▀▄▀▄▀▄▀▄
▄░█████▀▀█████░▄
▄███████░██░███████▄
▀▀██████▄▄██████▀▀
▀▀████████▀▀
.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
░▀▄░▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄░▄▀
███▀▄▀█████████████████▀▄▀
█████▀▄░▄▄▄▄▄███░▄▄▄▄▄▄▀
███████▀▄▀██████░█▄▄▄▄▄▄▄▄
█████████▀▄▄░███▄▄▄▄▄▄░▄▀
███████████░███████▀▄▀
███████████░██▀▄▄▄▄▀
███████████░▀▄▀
████████████▄▀
███████████
▄▄███████▄▄
▄████▀▀▀▀▀▀▀████▄
▄███▀▄▄███████▄▄▀███▄
▄██▀▄█▀▀▀█████▀▀▀█▄▀██▄
▄██▀▄███░░░▀████░███▄▀██▄
███░████░░░░░▀██░████░███
███░████░█▄░░░░▀░████░███
███░████░███▄░░░░████░███
▀██▄▀███░█████▄░░███▀▄██▀
▀██▄▀█▄▄▄██████▄██▀▄██▀
▀███▄▀▀███████▀▀▄███▀
▀████▄▄▄▄▄▄▄████▀
▀▀███████▀▀
OFFICIAL PARTNERSHIP
SOUTHAMPTON FC
FAZE CLAN
SSC NAPOLI
pooya87
Legendary
*
Offline Offline

Activity: 3934
Merit: 11905



View Profile
November 09, 2024, 06:20:50 AM
Merited by d5000 (3), ABCbits (2), Felicity_Tide (1)
 #2

The amount value can not be negative, we just have to check it to reject invalid amounts.

When you represent a number using a signed value type (in this case signed 64-bit integer called int64_t) you have to check for negative values. The condition can not just be <= max because for example negative one which is 0xFFFFFFFFFFFFFFFF is also smaller than max (0x000775f05a074000) and can only be rejected if you check the sign.

So when we check something like -1 we get to the first condition nValue >= 0 and since that is [false], and [false && whatever] is still false, then false is returned.

P.S. This conditional can be simplified by simply using an unsigned value type instead!
Although apparently since core uses the CAmount in wallet too and needs to represent negative values, they went with a signed value type.

BlackHatCoiner
Legendary
*
Offline Offline

Activity: 1792
Merit: 8695


View Profile
November 09, 2024, 08:58:32 AM
Merited by Felicity_Tide (1)
 #3

This is a question i could possibly answer while sleeping, but i haven't really done a research on why Bitcoin has to be measured in sats.
Because in 64 bits, you can represent anything from 1 satoshi, to 21 quadrillion satoshi, whereas if you used "Bitcoin" as a unit, you would need to make use of floating points, which complicates things for no reason. Floating points are useful, if we want to go beyond 21 million, or less than 0.00000001, and if precision does not matter, which is certainly not the case with a currency.

When you represent a number using a signed value type (in this case signed 64-bit integer called int64_t) you have to check for negative values.
I think his question boils down to "why does it use 'signed' if we do not use negative numbers?".

It's a good question, with no apparent answer AFAICS. Founder does not reply however.  Tongue
unsigned int is good until 2106.  Surely the network will have to be totally revamped at least once by then.

There should not be any signed int.  If you've found a signed int somewhere, please tell me (within the next 25 years please) and I'll change it to unsigned int.
pooya87
Legendary
*
Offline Offline

Activity: 3934
Merit: 11905



View Profile
November 09, 2024, 02:03:21 PM
Merited by BlackHatCoiner (4), ABCbits (2)
 #4

I think his question boils down to "why does it use 'signed' if we do not use negative numbers?".

It's a good question, with no apparent answer AFAICS. Founder does not reply however.  Tongue
unsigned int is good until 2106.  Surely the network will have to be totally revamped at least once by then.

There should not be any signed int.  If you've found a signed int somewhere, please tell me (within the next 25 years please) and I'll change it to unsigned int.
The response and the topic you shared is related to timestamps that can not handle year 2038 if signed int32 is used. It is not related to the signed int64 used for amounts.
The only thing we have about that is the following from bitcoin core dev Pieter Wuille:
CAmount is used for multiple purposes in Bitcoin Core, not just in transaction validation logic. It is also used to represent the net effect transactions have on wallet balance, for example, and that net effect is negative as often as it is positive.

garlonicon
Copper Member
Legendary
*
Offline Offline

Activity: 944
Merit: 2303


View Profile
November 10, 2024, 05:29:39 AM
Merited by pooya87 (2), ABCbits (2), Felicity_Tide (1)
 #5

Quote
How can the amount in satoshi be negative when any nValue aside the True condition must return false?
For example, you can make a transaction with negative fee:
Code:
+------------------------------------+
| Alice   1.00 BTC -> Bob   2.00 BTC |
+------------------------------------+
Then, you sign it with SIGHASH_SINGLE | SIGHASH_ANYONECANPAY. If you check fees for this specific partially signed transaction, you should see a negative value of -1.00 BTC. And then, Bob can claim it, by putting at least 1 BTC in another input. Example: https://bitcointalk.org/index.php?topic=5502111

Someone completed it on testnet3: https://mempool.space/testnet/tx/70f8a2d9e01f8603cc0301fe5b3b809c5a9acfc975a5f122393b1c900b977cba
Felicity_Tide (OP)
Sr. Member
****
Offline Offline

Activity: 518
Merit: 313


cout << "Bitcoin";


View Profile
November 10, 2024, 03:11:11 PM
 #6

The amount value can not be negative, we just have to check it to reject invalid amounts.

When you represent a number using a signed value type (in this case signed 64-bit integer called int64_t) you have to check for negative values. The condition can not just be <= max because for example negative one which is 0xFFFFFFFFFFFFFFFF is also smaller than max (0x000775f05a074000) and can only be rejected if you check the sign.

So when we check something like -1 we get to the first condition nValue >= 0 and since that is [false], and [false && whatever] is still false, then false is returned.

so basically, you are saying that we can't have a negative value, but the implementation of a signed 64-bit gives room to check for both positive values that are below the MAX, and negative values( which returns False if happens to be checked for) ?. I'm actually finding this very confusing, because from the explanation given below(using a tx as an example), it sounds theoretical to have a negative value(which comes in a form of fx fee), or does it mean that Alice's input will continue to return False, until Bob makes his own combined input alongside the tx fee, using a SIGHASH_SINGLE | SIGHASH_ANYONECANPAY ?.


Quote
How can the amount in satoshi be negative when any nValue aside the True condition must return false?
For example, you can make a transaction with negative fee:
Code:
+------------------------------------+
| Alice   1.00 BTC -> Bob   2.00 BTC |
+------------------------------------+
Then, you sign it with SIGHASH_SINGLE | SIGHASH_ANYONECANPAY. If you check fees for this specific partially signed transaction, you should see a negative value of -1.00 BTC. And then, Bob can claim it, by putting at least 1 BTC in another input. Example: https://bitcointalk.org/index.php?topic=5502111

Someone completed it on testnet3: https://mempool.space/testnet/tx/70f8a2d9e01f8603cc0301fe5b3b809c5a9acfc975a5f122393b1c900b977cba



Quote
P.S. This conditional can be simplified by simply using an unsigned value type instead!
Although apparently since core uses the CAmount in wallet too and needs to represent negative values, they went with a signed value type.

And maybe due to flexibility i guess, because i doubt if an unsigned-64bit can hold negative values unlike the signed-64bits that can hold both positive and negative values.

R


▀▀▀▀▀▀▀██████▄▄
████████████████
▀▀▀▀█████▀▀▀█████
████████▌███▐████
▄▄▄▄█████▄▄▄█████
████████████████
▄▄▄▄▄▄▄██████▀▀
LLBIT|
4,000+ GAMES
███████████████████
██████████▀▄▀▀▀████
████████▀▄▀██░░░███
██████▀▄███▄▀█▄▄▄██
███▀▀▀▀▀▀█▀▀▀▀▀▀███
██░░░░░░░░█░░░░░░██
██▄░░░░░░░█░░░░░▄██
███▄░░░░▄█▄▄▄▄▄████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
█████████
▀████████
░░▀██████
░░░░▀████
░░░░░░███
▄░░░░░███
▀█▄▄▄████
░░▀▀█████
▀▀▀▀▀▀▀▀▀
█████████
░░░▀▀████
██▄▄▀░███
█░░█▄░░██
░████▀▀██
█░░█▀░░██
██▀▀▄░███
░░░▄▄████
▀▀▀▀▀▀▀▀▀
|||
▄▄████▄▄
▀█▀
▄▀▀▄▀█▀
▄░░▄█░██░█▄░░▄
█░▄█░▀█▄▄█▀░█▄░█
▀▄░███▄▄▄▄███░▄▀
▀▀█░░░▄▄▄▄░░░█▀▀
░░██████░░█
█░░░░▀▀░░░░█
▀▄▀▄▀▄▀▄▀▄
▄░█████▀▀█████░▄
▄███████░██░███████▄
▀▀██████▄▄██████▀▀
▀▀████████▀▀
.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
░▀▄░▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄░▄▀
███▀▄▀█████████████████▀▄▀
█████▀▄░▄▄▄▄▄███░▄▄▄▄▄▄▀
███████▀▄▀██████░█▄▄▄▄▄▄▄▄
█████████▀▄▄░███▄▄▄▄▄▄░▄▀
███████████░███████▀▄▀
███████████░██▀▄▄▄▄▀
███████████░▀▄▀
████████████▄▀
███████████
▄▄███████▄▄
▄████▀▀▀▀▀▀▀████▄
▄███▀▄▄███████▄▄▀███▄
▄██▀▄█▀▀▀█████▀▀▀█▄▀██▄
▄██▀▄███░░░▀████░███▄▀██▄
███░████░░░░░▀██░████░███
███░████░█▄░░░░▀░████░███
███░████░███▄░░░░████░███
▀██▄▀███░█████▄░░███▀▄██▀
▀██▄▀█▄▄▄██████▄██▀▄██▀
▀███▄▀▀███████▀▀▄███▀
▀████▄▄▄▄▄▄▄████▀
▀▀███████▀▀
OFFICIAL PARTNERSHIP
SOUTHAMPTON FC
FAZE CLAN
SSC NAPOLI
odolvlobo
Legendary
*
Offline Offline

Activity: 4788
Merit: 3658



View Profile
November 10, 2024, 06:12:27 PM
Last edit: November 10, 2024, 07:06:16 PM by odolvlobo
Merited by pooya87 (4), ABCbits (4), vapourminer (1)
 #7

1. How can the amount in satoshi be negative when any nValue aside the True condition must return false?

I think you are misinterpreting the the code.

The variable type CAmount is a signed integer which means that variables of this type can hold both positive and negative numbers. That does not mean that a CAmount with a negative value is valid in every context. However, it allows for the possibility, and the comment (as I interpret it) is a warning that negative values are a possibility.

There can be instances where a negative value is reasonable. For example, when displaying the history of a wallet's balance, a transaction sending bitcoins from the wallet would show the change in the balance as a negative number of satoshis.

Finally, if you want to get into some C/C++ programming nitty-gritty ...

In C/C++, signed and unsigned integers are assigned to each other without conversion, so an unsigned integer variable can be assigned and can hold a negative value. A programmer might make the mistake of thinking that using an unsigned integer will somehow protect them from negative values, but it won't

A programmer may use an unsigned integer type to indicate that a variable is never expected to be negative, but that creates a false sense of security. In fact, it prevents them from verifying that value is not negative because the the value of an unsigned integer variable is always interpreted to be >= 0.

Consider that (unsigned)-2 >= 0, (unsigned)0 - (unsigned)2 == (unsigned)-2, and (unsigned)-2 + (unsigned)2 == 0 are all true.

So for those reasons, I never use unsigned integers for any variables involved in any mathematical operations, even if I never expect the values to ever be negative.

There is only one way to ensure that a variable is not negative and that is to allow it to be negative and then check its value, which is what the code you referenced does.

Join an anti-signature campaign: Click ignore on the members of signature campaigns.
PGP Fingerprint: 6B6BC26599EC24EF7E29A405EAF050539D0B2925 Signing address: 13GAVJo8YaAuenj6keiEykwxWUZ7jMoSLt
pooya87
Legendary
*
Offline Offline

Activity: 3934
Merit: 11905



View Profile
November 11, 2024, 01:50:39 PM
Merited by vapourminer (1), Felicity_Tide (1)
 #8

I'm actually finding this very confusing, because from the explanation given below(using a tx as an example), it sounds theoretical to have a negative value(which comes in a form of fx fee),
You still can't have a negative "amount" in your output. What is negative here is just the fee which is calculated on a higher level (usually for UI). But that can also be interpreted using unsigned integers as in "sum(output amounts >= sum(input amounts)".

And maybe due to flexibility i guess, because i doubt if an unsigned-64bit can hold negative values unlike the signed-64bits that can hold both positive and negative values.
If you really want to go down that rabbit hole, it may help if you think of numbers as binary values (as in zeros and ones), just like the computer does. There will no longer be any signed or unsigned values that way.
In fixed length numbers like (U)Int32 and (U)Int64 all the arithmetic is modular. So when you say -2 as a 32-bit number, that is congruent to 4294967294 and both of them are 0b11111111_11111111_11111111_11111110 in binary because the arithmetic here is modulo 4294967296 (=232).
That means the only reason why -2+2 is zero is because it overflows and we discard that extra 1.
  0b11111111_11111111_11111111_11111110 [=-2]
  0b00000000_00000000_00000000_00000010 [=2] +
---------------------------------------------
0b1_00000000_00000000_00000000_00000000 [=4294967296 % 4294967296 =0]


It may be easier to understand as 8-bit integers (1 byte) which can be from 0 (0x00) to 255 (0xff) and the arithmetic is modulo 256 (=28).
  0b11111110 [-2 ≡ 254 (mod 256)]
  0b00000010 [2] +
--------------------------
0b1_00000000 [254 + 2 ≡ 256 ≡ 0 (mod 256)]


So it really doesn't matter what value type you use to represent your numbers, the computer interprets them all the same. You just need have to be mindful of the type you used in your code.

Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!