github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/golomb_test.go (about)

     1  // //go:build unittest
     2  
     3  package bchain
     4  
     5  import (
     6  	"encoding/hex"
     7  	"testing"
     8  )
     9  
    10  func getCommonAddressDescriptors() []AddressDescriptor {
    11  	return []AddressDescriptor{
    12  		// bc1pgeqrcq5capal83ypxczmypjdhk4d9wwcea4k66c7ghe07p2qt97sqh8sy5
    13  		hexToBytes("512046403c0298e87bf3c4813605b2064dbdaad2b9d8cf6b6d6b1e45f2ff0540597d"),
    14  		// bc1p7en40zu9hmf9d3luh8evmfyg655pu5k2gtna6j7zr623f9tz7z0stfnwav
    15  		hexToBytes("5120f667578b85bed256c7fcb9f2cda488d5281e52ca42e7dd4bc21e95149562f09f"),
    16  		// 39ECUF8YaFRX7XfttfAiLa5ir43bsrQUZJ
    17  		hexToBytes("a91452ae9441d9920d9eb4a3c0a877ca8d8de547ce6587"),
    18  	}
    19  }
    20  
    21  func TestGolombFilter(t *testing.T) {
    22  	tests := []struct {
    23  		name               string
    24  		p                  uint8
    25  		useZeroedKey       bool
    26  		filterScripts      string
    27  		key                string
    28  		addressDescriptors []AddressDescriptor
    29  		wantError          bool
    30  		wantEnabled        bool
    31  		want               string
    32  	}{
    33  		{
    34  			name:               "taproot",
    35  			p:                  20,
    36  			useZeroedKey:       false,
    37  			filterScripts:      "taproot",
    38  			key:                "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
    39  			addressDescriptors: getCommonAddressDescriptors(),
    40  			wantEnabled:        true,
    41  			wantError:          false,
    42  			want:               "0235dddcce5d60",
    43  		},
    44  		{
    45  			name:               "taproot-zeroed-key",
    46  			p:                  20,
    47  			useZeroedKey:       true,
    48  			filterScripts:      "taproot",
    49  			key:                "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
    50  			addressDescriptors: getCommonAddressDescriptors(),
    51  			wantEnabled:        true,
    52  			wantError:          false,
    53  			want:               "0218c23a013600",
    54  		},
    55  		{
    56  			name:               "taproot p=21",
    57  			p:                  21,
    58  			useZeroedKey:       false,
    59  			filterScripts:      "taproot",
    60  			key:                "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
    61  			addressDescriptors: getCommonAddressDescriptors(),
    62  			wantEnabled:        true,
    63  			wantError:          false,
    64  			want:               "0235ddda672eb0",
    65  		},
    66  		{
    67  			name:               "all",
    68  			p:                  20,
    69  			useZeroedKey:       false,
    70  			filterScripts:      "",
    71  			key:                "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
    72  			addressDescriptors: getCommonAddressDescriptors(),
    73  			wantEnabled:        true,
    74  			wantError:          false,
    75  			want:               "0350ccc61ac611976c80",
    76  		},
    77  		{
    78  			name:               "taproot-noordinals",
    79  			p:                  20,
    80  			useZeroedKey:       false,
    81  			filterScripts:      "taproot-noordinals",
    82  			key:                "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
    83  			addressDescriptors: getCommonAddressDescriptors(),
    84  			wantEnabled:        true,
    85  			wantError:          false,
    86  			want:               "0235dddcce5d60",
    87  		},
    88  		{
    89  			name:          "not supported filter",
    90  			p:             20,
    91  			useZeroedKey:  false,
    92  			filterScripts: "notsupported",
    93  			wantEnabled:   false,
    94  			wantError:     true,
    95  			want:          "",
    96  		},
    97  		{
    98  			name:          "not enabled",
    99  			p:             0,
   100  			useZeroedKey:  false,
   101  			filterScripts: "",
   102  			wantEnabled:   false,
   103  			wantError:     false,
   104  			want:          "",
   105  		},
   106  	}
   107  	for _, tt := range tests {
   108  		t.Run(tt.name, func(t *testing.T) {
   109  			gf, err := NewGolombFilter(tt.p, tt.filterScripts, tt.key, tt.useZeroedKey)
   110  			if err != nil && !tt.wantError {
   111  				t.Errorf("TestGolombFilter.NewGolombFilter() got unexpected error '%v'", err)
   112  				return
   113  			}
   114  			if err == nil && tt.wantError {
   115  				t.Errorf("TestGolombFilter.NewGolombFilter() wanted error, got none")
   116  				return
   117  			}
   118  			if gf == nil && tt.wantError {
   119  				return
   120  			}
   121  			if gf.Enabled != tt.wantEnabled {
   122  				t.Errorf("TestGolombFilter.NewGolombFilter() got gf.Enabled %v, want %v", gf.Enabled, tt.wantEnabled)
   123  				return
   124  			}
   125  			for _, ad := range tt.addressDescriptors {
   126  				gf.AddAddrDesc(ad, nil)
   127  			}
   128  			f := gf.Compute()
   129  			got := hex.EncodeToString(f)
   130  			if got != tt.want {
   131  				t.Errorf("TestGolombFilter Compute() got %v, want %v", got, tt.want)
   132  			}
   133  		})
   134  	}
   135  }
   136  
   137  // Preparation transaction, locking BTC redeemable by ordinal witness - parent of the reveal transaction
   138  func getOrdinalCommitTx() (Tx, []AddressDescriptor) {
   139  	tx := Tx{
   140  		// https://mempool.space/tx/11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad
   141  		Txid: "11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad",
   142  		Vin: []Vin{
   143  			{
   144  				// https://mempool.space/tx/c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef
   145  				Txid: "c163fe1fdc21269cb05621adec38045e46a65289a356f9354df6010bce064916",
   146  				Vout: 0,
   147  				Witness: [][]byte{
   148  					hexToBytes("0371633164dd16345c02e80c9963042f9a502aa2c8109c0f61da333ac1503c3ce2a1b79895359bbdee5979ab2cb44f3395892e1c419c3a8f67d31d33d7e764c9"),
   149  				},
   150  			},
   151  		},
   152  		Vout: []Vout{
   153  			{
   154  				ScriptPubKey: ScriptPubKey{
   155  					Hex: "51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff",
   156  					Addresses: []string{
   157  						"bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0",
   158  					},
   159  				},
   160  			},
   161  			{
   162  				ScriptPubKey: ScriptPubKey{
   163  					Hex: "a9144390d0b3d2b6d48b8c205ffbe40b2d84c40de07f87",
   164  					Addresses: []string{
   165  						"37rGgLSLX6C6LS9am4KWd6GT1QCEP4H4py",
   166  					},
   167  				},
   168  			},
   169  			{
   170  				ScriptPubKey: ScriptPubKey{
   171  					Hex: "76a914ba6b046dd832aa8bc41c158232bcc18211387c4388ac",
   172  					Addresses: []string{
   173  						"1HzgtNdRCXszf95rFYemsDSHJQBbs9rbZf",
   174  					},
   175  				},
   176  			},
   177  		},
   178  	}
   179  	addressDescriptors := []AddressDescriptor{
   180  		// bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0
   181  		hexToBytes("51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff"),
   182  		// 37rGgLSLX6C6LS9am4KWd6GT1QCEP4H4py
   183  		hexToBytes("a9144390d0b3d2b6d48b8c205ffbe40b2d84c40de07f87"),
   184  		// 1HzgtNdRCXszf95rFYemsDSHJQBbs9rbZf
   185  		hexToBytes("76a914ba6b046dd832aa8bc41c158232bcc18211387c4388ac"),
   186  	}
   187  	return tx, addressDescriptors
   188  }
   189  
   190  // Transaction containing the actual ordinal data in witness - child of the commit transaction
   191  func getOrdinalRevealTx() (Tx, []AddressDescriptor) {
   192  	tx := Tx{
   193  		// https://mempool.space/tx/c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef
   194  		Txid: "c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef",
   195  		Vin: []Vin{
   196  			{
   197  				Txid: "11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad",
   198  				Vout: 0,
   199  				Witness: [][]byte{
   200  					hexToBytes("737ad2835962e3d147cd74a578f1109e9314eac9d00c9fad304ce2050b78fac21a2d124fd886d1d646cf1de5d5c9754b0415b960b1319526fa25e36ca1f650ce"),
   201  					hexToBytes("2029f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328ac0063036f726401010a696d6167652f77656270004d08025249464650020000574542505650384c440200002f57c2950067a026009086939b7785a104699656f4f53388355445b6415d22f8924000fd83bd31d346ca69f8fcfed6d8d18231846083f90f00ffbf203883666c36463c6ba8662257d789935e002192245bd15ac00216b080052cac85b380052c60e1593859f33a7a7abff7ed88feb361db3692341bc83553aef7aec75669ffb1ffd87fec3ff61ffb8ffdc736f20a96a0fba34071d4fdf111c435381df667728f95c4e82b6872d82471bfdc1665107bb80fd46df1686425bcd2e27eb59adc9d17b54b997ee96776a7c37ca2b57b9551bcffeb71d88768765af7384c2e3ba031ca3f19c9ddb0c6ec55223fbfe3731a1e8d7bb010de8532d53293bbbb6145597ee53559a612e6de4f8fc66936ef463eea7498555643ac0dafad6627575f2733b9fb352e411e7d9df8fc80fde75f5f66f5c5381a46b9a697d9c97555c4bf41a4909b9dd071557c3dfe0bfcd6459e06514266c65756ce9f25705230df63d30fef6076b797e1f49d00b41e87b5ccecb1c237f419e4b3ca6876053c14fc979a629459a62f78d735fb078bfa0e7a1fc69ad379447d817e06b3d7f1de820f28534f85fa20469cd6f93ddc6c5f2a94878fc64a98ac336294c99d27d11742268ae1a34cd61f31e2e4aee94b0ff496f55068fa727ace6ad2ec1e6e3f59e6a8bd154f287f652fbfaa05cac067951de1bfacc0e330c3bf6dd2efde4c509646566836eb71986154731daf722a6ff585001e87f9479559a61265d6e330f3682bf87ab2598fc3fca36da778e59cee71584594ef175e6d7d5f70d6deb02c4b371e5063c35669ffb1ffd87ffe0e730068"),
   202  					hexToBytes("c129f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328"),
   203  				},
   204  			},
   205  		},
   206  		Vout: []Vout{
   207  			{
   208  				ScriptPubKey: ScriptPubKey{
   209  					Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
   210  					Addresses: []string{
   211  						"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
   212  					},
   213  				},
   214  			},
   215  		},
   216  	}
   217  	addressDescriptors := []AddressDescriptor{
   218  		// bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta
   219  		hexToBytes("51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a"),
   220  	}
   221  	return tx, addressDescriptors
   222  }
   223  
   224  func TestGolombIsOrdinal(t *testing.T) {
   225  	revealTx, _ := getOrdinalRevealTx()
   226  	if txContainsOrdinal(&revealTx) != true {
   227  		t.Error("Ordinal not found in reveal Tx")
   228  	}
   229  	commitTx, _ := getOrdinalCommitTx()
   230  	if txContainsOrdinal(&commitTx) != false {
   231  		t.Error("Ordinal found in commit Tx, but should not be there")
   232  	}
   233  }
   234  
   235  func TestGolombOrdinalTransactions(t *testing.T) {
   236  	tests := []struct {
   237  		name          string
   238  		filterScripts string
   239  		want          string
   240  	}{
   241  		{
   242  			name:          "all",
   243  			filterScripts: "",
   244  			want:          "04256e660160e42ff40ee320", // take all four descriptors
   245  		},
   246  		{
   247  			name:          "taproot",
   248  			filterScripts: "taproot",
   249  			want:          "0212b734c2ebe0", // filter out two non-taproot ones
   250  		},
   251  		{
   252  			name:          "taproot-noordinals",
   253  			filterScripts: "taproot-noordinals",
   254  			want:          "", // ignore everything
   255  		},
   256  	}
   257  	for _, tt := range tests {
   258  		t.Run(tt.name, func(t *testing.T) {
   259  			gf, err := NewGolombFilter(20, tt.filterScripts, "", true)
   260  			if err != nil {
   261  				t.Errorf("TestGolombOrdinalTransactions.NewGolombFilter() got unexpected error '%v'", err)
   262  				return
   263  			}
   264  
   265  			commitTx, addressDescriptorsCommit := getOrdinalCommitTx()
   266  			revealTx, addressDescriptorsReveal := getOrdinalRevealTx()
   267  
   268  			for _, ad := range addressDescriptorsCommit {
   269  				gf.AddAddrDesc(ad, &commitTx)
   270  			}
   271  			for _, ad := range addressDescriptorsReveal {
   272  				gf.AddAddrDesc(ad, &revealTx)
   273  			}
   274  
   275  			f := gf.Compute()
   276  			got := hex.EncodeToString(f)
   277  			if got != tt.want {
   278  				t.Errorf("TestGolombOrdinalTransactions Compute() got %v, want %v", got, tt.want)
   279  			}
   280  		})
   281  	}
   282  }