Skip to content

Commit 723c4ed

Browse files
committed
Add CashTokens core logic
1 parent 9dfc103 commit 723c4ed

14 files changed

Lines changed: 599 additions & 74 deletions

File tree

blockchain/compress.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func isScriptHash(script []byte) (bool, []byte) {
207207
func isScriptHash32(script []byte) (bool, []byte) {
208208
if len(script) == 35 && script[0] == txscript.OP_HASH256 &&
209209
script[1] == txscript.OP_DATA_32 &&
210-
script[22] == txscript.OP_EQUAL {
210+
script[34] == txscript.OP_EQUAL {
211211

212212
return true, script[2:34]
213213
}

blockchain/scriptval.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ out:
7777
sigScript := txIn.SignatureScript
7878
pkScript := utxo.PkScript()
7979
inputAmount := utxo.Amount()
80+
tokenData := utxo.tokenData
8081

8182
utxoEntryCache := txscript.NewUtxoCache()
8283
for i, in := range txVI.tx.MsgTx().TxIn {
8384
if i == txVI.txInIndex {
84-
utxoEntryCache.AddEntry(i, *wire.NewTxOut(utxo.amount, utxo.pkScript))
85+
utxoEntryCache.AddEntry(i, *wire.NewTxOut(utxo.amount, utxo.pkScript, tokenData))
8586
continue
8687
}
8788
u := v.utxoView.LookupEntry(in.PreviousOutPoint)
@@ -95,7 +96,7 @@ out:
9596
v.sendResult(err)
9697
break out
9798
}
98-
utxoEntryCache.AddEntry(i, *wire.NewTxOut(u.amount, u.pkScript))
99+
utxoEntryCache.AddEntry(i, *wire.NewTxOut(u.amount, u.pkScript, u.tokenData))
99100
}
100101

101102
vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(),
@@ -255,6 +256,19 @@ func ValidateTransactionScripts(tx *bchutil.Tx, utxoView *UtxoViewpoint,
255256
cachedHashes = txscript.NewTxSigHashes(tx.MsgTx())
256257
}
257258

259+
if cachedHashes != nil {
260+
utxoCache := txscript.NewUtxoCache()
261+
for i, in := range tx.MsgTx().TxIn {
262+
u := utxoView.LookupEntry(in.PreviousOutPoint)
263+
if u == nil {
264+
break // Raise error?
265+
}
266+
utxoCache.AddEntry(i, *wire.NewTxOut(u.amount, u.pkScript, u.tokenData))
267+
}
268+
269+
cachedHashes.AddTxSigHashUtxoFromUtxoCache(tx.MsgTx(), utxoCache)
270+
}
271+
258272
// Collect all of the transaction inputs and required information for
259273
// validation.
260274
sigChecks := uint32(0)
@@ -319,6 +333,19 @@ func checkBlockScripts(block *bchutil.Block, utxoView *UtxoViewpoint,
319333
cachedHashes = txscript.NewTxSigHashes(tx.MsgTx())
320334
}
321335

336+
if cachedHashes != nil {
337+
utxoCache := txscript.NewUtxoCache()
338+
for i, in := range tx.MsgTx().TxIn {
339+
u := utxoView.LookupEntry(in.PreviousOutPoint)
340+
if u == nil {
341+
break // Raise error?
342+
}
343+
utxoCache.AddEntry(i, *wire.NewTxOut(u.amount, u.pkScript, u.tokenData))
344+
}
345+
346+
cachedHashes.AddTxSigHashUtxoFromUtxoCache(tx.MsgTx(), utxoCache)
347+
}
348+
322349
for txInIdx, txIn := range tx.MsgTx().TxIn {
323350
// Skip coinbases.
324351
if txIn.PreviousOutPoint.Index == math.MaxUint32 {

blockchain/utxocache.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ type UtxoEntry struct {
7373
pkScript []byte // The public key script for the output.
7474
blockHeight int32 // Height of block containing tx.
7575

76+
tokenData wire.TokenData // TODO this can use better memorry optimization. Check the paddings.
77+
7678
// packedFlags contains additional info about output such as whether it
7779
// is a coinbase, whether it is spent, and whether it has been modified
7880
// since it was loaded. This approach is used in order to reduce memory
@@ -90,6 +92,7 @@ func NewUtxoEntry(txOut *wire.TxOut, blockHeight int32, isCoinbase bool) *UtxoEn
9092
return &UtxoEntry{
9193
amount: txOut.Value,
9294
pkScript: txOut.PkScript,
95+
tokenData: txOut.TokenData,
9396
blockHeight: blockHeight,
9497
packedFlags: cbFlag,
9598
}
@@ -145,6 +148,8 @@ func (entry *UtxoEntry) memoryUsage() uint64 {
145148
// unsafe.Sizeof(UtxoEntry{})
146149
baseEntrySize := uint64(40)
147150

151+
baseEntrySize += uint64(88) // Size of TokenData
152+
148153
return baseEntrySize + uint64(len(entry.pkScript))
149154
}
150155

@@ -169,6 +174,7 @@ func (entry *UtxoEntry) Clone() *UtxoEntry {
169174
return &UtxoEntry{
170175
amount: entry.amount,
171176
pkScript: entry.pkScript,
177+
tokenData: entry.tokenData,
172178
blockHeight: entry.blockHeight,
173179
packedFlags: entry.packedFlags,
174180
}

blockchain/utxoviewpoint.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ func addTxOuts(view utxoView, tx *bchutil.Tx, blockHeight int32, overwrite bool)
189189
entry := &UtxoEntry{
190190
amount: txOut.Value,
191191
pkScript: pkScript,
192+
tokenData: txOut.TokenData,
192193
blockHeight: blockHeight,
193194
packedFlags: tfModified,
194195
}
@@ -339,8 +340,10 @@ func disconnectTransactions(view utxoView, block *bchutil.Block, stxos []SpentTx
339340
copy(pkScript, stxo.PkScript)
340341

341342
entry := &UtxoEntry{
342-
amount: stxo.Amount,
343-
pkScript: pkScript,
343+
amount: stxo.Amount,
344+
pkScript: pkScript,
345+
// tokenData: stxo.tokenData,
346+
// TODO TODO SpentTxOut
344347
blockHeight: stxo.Height,
345348
packedFlags: tfModified,
346349
}
@@ -391,6 +394,7 @@ func disconnectTransactions(view utxoView, block *bchutil.Block, stxos []SpentTx
391394
entry := &UtxoEntry{
392395
amount: txOut.Value,
393396
pkScript: pkScript,
397+
tokenData: txOut.TokenData,
394398
blockHeight: block.Height(),
395399
packedFlags: packedFlags,
396400
}

blockchain/validate.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,17 @@ func CheckTransactionSanity(tx *bchutil.Tx, magneticAnomalyActive bool, upgrade9
260260
return ruleError(ErrTxTooBig, str)
261261
}
262262

263-
if magneticAnomalyActive && serializedTxSize < MagneticAnomalyMinTransactionSize {
263+
if magneticAnomalyActive || upgrade9Active {
264264
minTxSize := MagneticAnomalyMinTransactionSize
265265
if upgrade9Active {
266266
minTxSize = MinTransactionSize
267267
}
268-
str := fmt.Sprintf("serialized transaction is too small - got "+
269-
"%d, min %d", serializedTxSize, minTxSize)
270-
return ruleError(ErrTxTooSmall, str)
268+
if serializedTxSize < minTxSize {
269+
270+
str := fmt.Sprintf("serialized transaction is too small - got "+
271+
"%d, min %d", serializedTxSize, minTxSize)
272+
return ruleError(ErrTxTooSmall, str)
273+
}
271274
}
272275

273276
// Ensure the transaction amounts are in range. Each transaction
@@ -1014,6 +1017,8 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *bchutil.Block, vi
10141017
// If CosmicInflation is active we enforce 64BitIntegers and NativeIntrospection
10151018
cosmicInflationActive := node.parent.CalcPastMedianTime().Unix() >= int64(b.chainParams.CosmicInflationActivationTime)
10161019

1020+
upgrade9Active := node.height > b.chainParams.Upgrade9ForkHeight
1021+
10171022
// BIP0030 added a rule to prevent blocks which contain duplicate
10181023
// transactions that 'overwrite' older transactions which are not fully
10191024
// spent. See the documentation for checkBIP0030 for more details.
@@ -1113,6 +1118,10 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *bchutil.Block, vi
11131118
scriptFlags |= txscript.ScriptVerify64BitIntegers | txscript.ScriptVerifyNativeIntrospection
11141119
}
11151120

1121+
if upgrade9Active {
1122+
scriptFlags |= txscript.ScriptAllowSighashUTXO
1123+
}
1124+
11161125
// Perform several checks on the inputs for each transaction. Also
11171126
// accumulate the total fees. This could technically be combined with
11181127
// the loop above instead of running another loop over the transactions,

chaincfg/params.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ var ChipNetParams = Params{
651651
GravitonForkHeight: 4999,
652652
PhononForkHeight: 0,
653653
AxionActivationHeight: 16844,
654+
Upgrade9ForkHeight: 121956,
654655

655656
CosmicInflationActivationTime: 1637694000,
656657

netsync/manager.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) {
801801

802802
// If we didn't ask for this block then the peer is misbehaving.
803803
blockHash := bmsg.block.Hash()
804+
804805
if _, exists = state.requestedBlocks[*blockHash]; !exists && !peer.AllowDirectBlockRelay() {
805806
// The regression test intentionally sends some blocks twice
806807
// to test duplicate block insertion fails. Don't disconnect

rpcserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeNotifier <-c
609609
return nil, internalRPCError(err.Error(), context)
610610
}
611611

612-
txOut := wire.NewTxOut(int64(satoshi), pkScript)
612+
txOut := wire.NewTxOut(int64(satoshi), pkScript, wire.TokenData{}) // TODO TODO FIX THIS! This shouldn't be an empty token data
613613
mtx.AddTxOut(txOut)
614614
}
615615

txscript/engine.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ const (
127127
// ScriptVerifyNativeIntrospection enables the suite of native introspection
128128
// opcodes.
129129
ScriptVerifyNativeIntrospection
130+
131+
// ScriptAllowSighashUTXO enables the use of SighashUTXO signing serialization type
132+
ScriptAllowSighashUTXO
130133
)
131134

132135
// HasFlag returns whether the ScriptFlags has the passed flag set.
@@ -375,6 +378,7 @@ func (vm *Engine) Step() (done bool, err error) {
375378
if err != nil {
376379
return true, err
377380
}
381+
378382
opcode := &vm.scripts[vm.scriptIdx][vm.scriptOff]
379383
vm.scriptOff++
380384

@@ -502,6 +506,20 @@ func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
502506
}
503507
}
504508

509+
if vm.hasFlag(ScriptAllowSighashUTXO) {
510+
sigHashType &= ^SigHashUTXO
511+
} else {
512+
if hashType&SigHashUTXO != 0 {
513+
str := fmt.Sprintf("invalid hash type containing SIGHASH_UTXOS 0x%x", hashType)
514+
return scriptError(ErrInvalidSigHashType, str)
515+
}
516+
}
517+
518+
if hashType&SigHashUTXO != 0 && hashType&SigHashAnyOneCanPay != 0 {
519+
str := fmt.Sprintf("invalid hash type containing both SIGHASH_UTXOS and SIGHASH_ANYONECANPAY 0x%x", hashType)
520+
return scriptError(ErrInvalidSigHashType, str)
521+
}
522+
505523
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
506524
str := fmt.Sprintf("invalid hash type 0x%x", hashType)
507525
return scriptError(ErrInvalidSigHashType, str)
@@ -954,6 +972,16 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags
954972
}
955973
vm.bip16 = true
956974
}
975+
976+
if vm.hasFlag(ScriptBip16) && isScriptHash32(vm.scripts[1]) {
977+
// Only accept input scripts that push data for P2SH.
978+
if !isPushOnly(vm.scripts[0]) {
979+
return nil, scriptError(ErrNotPushOnly,
980+
"pay to script hash is not push only")
981+
}
982+
vm.bip16 = true
983+
}
984+
957985
if vm.hasFlag(ScriptVerifyMinimalData) {
958986
vm.dstack.verifyMinimalData = true
959987
vm.astack.verifyMinimalData = true

txscript/hashcache.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ import (
1717
// transaction when validating all inputs. As a result, validation complexity
1818
// for SigHashAll can be reduced by a polynomial factor.
1919
type TxSigHashes struct {
20-
HashPrevOuts chainhash.Hash
21-
HashSequence chainhash.Hash
22-
HashOutputs chainhash.Hash
20+
HashPrevOuts chainhash.Hash
21+
HashSequence chainhash.Hash
22+
HashOutputs chainhash.Hash
23+
HashUTXOS chainhash.Hash
24+
tokenDataList [][]byte
2325
}
2426

2527
// NewTxSigHashes computes, and returns the cached sighashes of the given
@@ -29,9 +31,17 @@ func NewTxSigHashes(tx *wire.MsgTx) *TxSigHashes {
2931
HashPrevOuts: calcHashPrevOuts(tx),
3032
HashSequence: calcHashSequence(tx),
3133
HashOutputs: calcHashOutputs(tx),
34+
// HashUTXOS: calcHashUtxos(tx),
35+
HashUTXOS: chainhash.Hash{},
3236
}
3337
}
3438

39+
func (txSighashes *TxSigHashes) AddTxSigHashUtxoFromUtxoCache(tx *wire.MsgTx, utxoCache *UtxoCache) {
40+
hash := calcHashUtxos(tx, utxoCache)
41+
txSighashes.HashUTXOS = hash
42+
txSighashes.tokenDataList = calUtxoTokenData(tx, utxoCache)
43+
}
44+
3545
// HashCache houses a set of partial sighashes keyed by txid. The set of partial
3646
// sighashes are those introduced within BIP0143 by the new more efficient
3747
// sighash digest calculation algorithm. Using this threadsafe shared cache,

0 commit comments

Comments
 (0)