github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/textui/consensus/consensus_linux.go (about) 1 // +build linux 2 3 // Place the bitcoin consensus lib (libbitcoinconsensus.so) where OS can find it. 4 // If this file does not build and you don't know what to do, just delete it 5 6 package textui 7 8 /* 9 #cgo LDFLAGS: -ldl 10 11 #include <stdio.h> 12 #include <dlfcn.h> 13 14 15 typedef signed long long int64_t; 16 17 unsigned int (*_bitcoinconsensus_version)(); 18 19 int (*_bitcoinconsensus_verify_script_with_amount)(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount, 20 const unsigned char *txTo , unsigned int txToLen, 21 unsigned int nIn, unsigned int flags, void* err); 22 23 int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount, 24 const unsigned char *txTo , unsigned int txToLen, 25 unsigned int nIn, unsigned int flags) { 26 return _bitcoinconsensus_verify_script_with_amount(scriptPubKey, scriptPubKeyLen, amount, txTo, txToLen, nIn, flags, NULL); 27 } 28 29 unsigned int bitcoinconsensus_version() { 30 return _bitcoinconsensus_version(); 31 } 32 33 int init_bitcoinconsensus_so() { 34 void *so = dlopen("libbitcoinconsensus.so", RTLD_LAZY); 35 if (so) { 36 *(void **)(&_bitcoinconsensus_version) = dlsym(so, "bitcoinconsensus_version"); 37 *(void **)(&_bitcoinconsensus_verify_script_with_amount) = dlsym(so, "bitcoinconsensus_verify_script_with_amount"); 38 if (!_bitcoinconsensus_version) { 39 printf("libbitcoinconsensus.so not found\n"); 40 return 0; 41 } 42 if (!_bitcoinconsensus_verify_script_with_amount) { 43 printf("libbitcoinconsensus.so is too old. Use one of bitcoin-core 0.13.1\n"); 44 return 0; 45 } 46 return 1; 47 } 48 return 0; 49 } 50 51 */ 52 import "C" 53 54 import ( 55 "encoding/hex" 56 "fmt" 57 "github.com/piotrnar/gocoin/client/common" 58 "github.com/piotrnar/gocoin/lib/btc" 59 "github.com/piotrnar/gocoin/lib/script" 60 "sync" 61 "sync/atomic" 62 "unsafe" 63 ) 64 65 var ( 66 ConsensusChecks uint64 67 ConsensusExpErr uint64 68 ConsensusErrors uint64 69 mut sync.Mutex 70 ) 71 72 func check_consensus(pkScr []byte, amount uint64, i int, tx *btc.Tx, ver_flags uint32, result bool) { 73 var tmp []byte 74 if len(pkScr) != 0 { 75 tmp = make([]byte, len(pkScr)) 76 copy(tmp, pkScr) 77 } 78 tx_raw := tx.Raw 79 if tx_raw == nil { 80 tx_raw = tx.Serialize() 81 } 82 go func(pkScr []byte, txTo []byte, amount uint64, i int, ver_flags uint32, result bool) { 83 var pkscr_ptr *C.uchar // default to null 84 var pkscr_len C.uint // default to 0 85 if pkScr != nil { 86 pkscr_ptr = (*C.uchar)(unsafe.Pointer(&pkScr[0])) 87 pkscr_len = C.uint(len(pkScr)) 88 } 89 r1 := int(C.bitcoinconsensus_verify_script_with_amount(pkscr_ptr, pkscr_len, C.int64_t(amount), 90 (*C.uchar)(unsafe.Pointer(&txTo[0])), C.uint(len(txTo)), C.uint(i), C.uint(ver_flags))) 91 res := r1 == 1 92 atomic.AddUint64(&ConsensusChecks, 1) 93 if !result { 94 atomic.AddUint64(&ConsensusExpErr, 1) 95 } 96 if res != result { 97 atomic.AddUint64(&ConsensusErrors, 1) 98 common.CountSafe("TxConsensusERR") 99 mut.Lock() 100 println("Compare to consensus failed!") 101 println("Gocoin:", result, " ConsLIB:", res) 102 println("pkScr", hex.EncodeToString(pkScr)) 103 println("txTo", hex.EncodeToString(txTo)) 104 println("amount:", amount, " input_idx:", i, " ver_flags:", ver_flags) 105 println() 106 mut.Unlock() 107 } 108 }(tmp, tx_raw, amount, i, ver_flags, result) 109 } 110 111 func verify_script_with_amount(pkScr []byte, amount uint64, i int, tx *btc.Tx, ver_flags uint32) (result bool) { 112 txTo := tx.Raw 113 if txTo == nil { 114 txTo = tx.Serialize() 115 } 116 var pkscr_ptr *C.uchar // default to null 117 var pkscr_len C.uint // default to 0 118 if pkScr != nil { 119 pkscr_ptr = (*C.uchar)(unsafe.Pointer(&pkScr[0])) 120 pkscr_len = C.uint(len(pkScr)) 121 } 122 r1 := int(C.bitcoinconsensus_verify_script_with_amount(pkscr_ptr, pkscr_len, C.int64_t(amount), 123 (*C.uchar)(unsafe.Pointer(&txTo[0])), C.uint(len(txTo)), C.uint(i), C.uint(ver_flags))) 124 125 result = (r1 == 1) 126 return 127 } 128 129 func consensus_stats(s string) { 130 fmt.Println("Consensus Checks:", atomic.LoadUint64(&ConsensusChecks)) 131 fmt.Println("Consensus ExpErr:", atomic.LoadUint64(&ConsensusExpErr)) 132 fmt.Println("Consensus Errors:", atomic.LoadUint64(&ConsensusErrors)) 133 } 134 135 func init() { 136 if C.init_bitcoinconsensus_so() == 0 { 137 common.Log.Println("Not using libbitcoinconsensus.so to cross-check consensus rules") 138 return 139 } 140 common.Log.Println("Using libbitcoinconsensus.so version", C.bitcoinconsensus_version(), "to cross-check consensus") 141 script.VerifyConsensus = check_consensus 142 newUi("cons", false, consensus_stats, "See statistics of the consensus cross-checks") 143 }