Cryddit you are still incorrect as the size of inputs and outputs can vary, bitcoin supports compressed keys and it is the default key type for most wallets now.
It is very important when providing corrections to get the data correct. The data in the wiki is correct. Not really sure I see the point to providing an alternate explanation which gets material facts wrong and requires three corrections and even then is only 95% correct.
When you provide exact values like 12 + 204 * (# inputs) + 32 * (# outputs) it creates a perception that this is the exact and only value. Far better to say in aproximations. Also the client is going to do the work on computing the required fee. Not sure where you got the 12 from but it is incorrect (or not correct for all txs) and the 204 assumes the use of uncompressed keys which is uncommon at this time.
The objective here is that people should be able to
PREDICT what a given transaction will owe in fees rather than having it lie latent and
UNKNOWABLE in software until the time comes to pay them, and for people to have truth in order to NOT be misled by misinformation such as that which I myself was spreading earlier in this thread. If people can predict fees in some kind of definite way, then they can understand, for example, when and why it is against their interests and unsupported by pools and merchants to take payments in "dust," when and why and how much bitcoin has a problem scaling to very small payments or vast numbers of transactions, when and why they cannot in fact make a 5.00000 bitcoin payment when they have exactly 5.00000 bitcoins in their wallet (which can save a hell of a lot of miscalculation, embarrassment, and possibly expense if they have the misfortune to have already agreed to make this payment).
Therefore it is completely unacceptable that a procedure should estimate too low, and highly undesirable for it to estimate too high; in fact it would be best if fees did not have to be estimated at all. It is also unacceptable to not know fees until you come to the point of actually making a payment. It must not lie latent and unknowable in software until that point. And because it does not correlate with the amount sent, people do not otherwise understand it at all. So please; DON'T just tell me something is wrong; tell me instead exactly how to correct it.
Hopefully you find this helpful.
https://en.bitcoin.it/w/images/en/e/e1/TxBinaryMap.pngI understand your intent although most people have no idea how many inputs they have so it isn't all that useful. I do agree it would be useful if the client showed the balance and available to spend which accounted for any required fees thus people would know how much they can spend (possibly including optional fees). My point is if you are going to provide numbers make sure they are right or phrase them as a question. Bitcoin is very information dense and incorrect values just make it that much harder for new people to learn. I would recommend blockexplorer.com as a resource for viewing raw tx to see what the inputs and outputs look like. Be warned though for some reason blockexplorer (and bitcoind) drop some of the length values which makes it difficulty to compare to the map above.
You stated (paraphrased)
size in bytes = 12 + 204 * (# inputs) + 32 * (# outputs)
I
believe that is incorrect for a number of reasons.
Disclaimer: this is only for standard "paytoPubKeyHash" (what most users consider normal) transactions which have <= 253 inputs and outputs and lack any complex scripting.
AFAIK this is the structure of transactions:
Header
-------------------------------
Version = 4 bytes
NumTxIn = 1 byte (technically a VarInt but it is 1 byte up to 253 <- note it is 253 not 255)
NumTxOut = 1 byte (also a Varint = same as above)
LockTime = 4 bytes
-------------------------------
Total = 10 bytes
Inputs
------------------------------
TxOutHash = 32 bytes
TxOutIndex = 4 bytes <- not sure why developers didn't make this a varint would save 3 bytes on most transactions
ScriptLen = 1 byte (technically varint but will be <253 bytes for "standard" inputs)
Script = 106 bytes (138 bytes for uncompressed keys)
Sequence = 4 bytes
-------------
Total = 147 bytes (179 for uncompressed keys)
The input script depends on the requirements set in the output but for standard PayToPubKeyHash outputs it consists of:
Padding & Length values = 10 bytes
Sig r = 32 bytes (random nonce)
Sig s = 32 bytes (signature)
Key x = 32 bytes
Key y = 32 bytes (committed for compressed keys)
----------------------
Total 106 bytes (138 bytes for uncompressed keys)
Output
------------------------------
Value = 8 bytes
ScriptLen = 1 byte
OutputScript = 25 bytes (for standard "pay to pubkeyhash").
Breakdown of output script (standard "pay to pubkeyhash")
---------------------------------------------------------
OP_DUP = 1 byte
OP_HASH160 = 1 byte
0x14 = 1 byte
PubKeyHash = 20 bytes (RIPEMD-160 = 160 bits = 20 bytes)
OP_EQUALVERIFY = 1 byte
OP_CHECKSIG = 1 byte
----------------------------------------------
Total = 33 bytes
So for most cases the size of a tx is:
TxSize (bytes) = 10 + (NumInputs * 147) + (NumOutputs * 33)
The wiki was ambiguous regarding the size of keys for inputs. On the information provided (some of which it was necessary to read binary to find) they could either be 41 or 65 bytes long and I couldn't find *ANYTHING* in any human language that said which value was in actual use on the wiki. I eventually used 65 bytes because I found a binary dump of a protocol exchange on the wiki that used 65 bytes. If the 41-byte key form is in actual use, then transactions may be 24 bytes per input shorter.
It is important to understand that various core data elements (pubkeys, addresses, private keys, etc) have a variety of forms. The WIF private key form is base58 and indcludes a checksum (to avoid errors when manually copying). At the transaction level everything is "raw" in binary without any encoding. For example pubkeys are stored as x & y values thus they will be 32 or 64 bytes (compressed pubkeys ommit the y value since it can be computed). Although at the user level we may send to an address, since addresses can be converted to pubkeys (and pubkeys to addresses) at the tx level the standard tx is "Pay To PubKeyHash" not "Pay To Address" so the PubKey is used in the output script and that is always exactly 20 bytes.
Is there any way to tell which format the unspent tx in your wallet are? If this is necessary in order to predict fees then people need to know it.
Yes. In WIF (Wallet Import Format) the private keys for compressed pubkeys begin with 5. This is not a requirement of ECDSA as private keys are simply 256 bit numbers it is a Bitcoin standard to allow one to "know" if the resulting pubkey should be in compressed or uncompressed format. The resulting address will be different. Since the address is a hash you can't tell from the address alone. You need either the private key or the pubkey. Sadly there is absolutely no reason for uncompressed keys. They just take up more space and make everything more confusing (two pubkey standards). It would seem Satoshi was unaware of some cryptograpihc "best practices".
If someone wanted to make an improved altcoin (as opposed to pump and dump nonsense) there are a lot of low level improvements which could be done that would simplify the codebase and make it easier to understand for new developers.
Off the top of my head:
Enforce use of compressed keys only.
Implement PubKey recovery to avoid needing to put pubkey in the tx input (would save 33 bytes per input per tx)
Make fees explicitly part of tx rather than implicit (avoids coins lost to miners in errors)
Use a canonical form of signing and make any non canonical form an invalid transaction (would seal up a lot of subtle security issues)