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  }