|
4 | 4 | "bytes" |
5 | 5 | "context" |
6 | 6 | "crypto/sha256" |
| 7 | + "database/sql" |
7 | 8 | "math/rand" |
8 | 9 | "sort" |
9 | 10 | "testing" |
@@ -1897,3 +1898,241 @@ func TestFetchGroupedAssets(t *testing.T) { |
1897 | 1898 | equalityCheck(allAssets[2].Asset, groupedAssets[1]) |
1898 | 1899 | equalityCheck(allAssets[3].Asset, groupedAssets[2]) |
1899 | 1900 | } |
| 1901 | + |
| 1902 | +// TestTransferOutputProofDeliveryStatus tests that we can properly set the |
| 1903 | +// proof delivery status of a transfer output. |
| 1904 | +func TestTransferOutputProofDeliveryStatus(t *testing.T) { |
| 1905 | + t.Parallel() |
| 1906 | + |
| 1907 | + // First, we'll create a new assets store. We'll use this to store the |
| 1908 | + // asset and the outbound parcel in the database. |
| 1909 | + _, assetsStore, db := newAssetStore(t) |
| 1910 | + ctx := context.Background() |
| 1911 | + |
| 1912 | + // Generate a single asset. |
| 1913 | + targetScriptKey := asset.NewScriptKeyBip86(keychain.KeyDescriptor{ |
| 1914 | + PubKey: test.RandPubKey(t), |
| 1915 | + KeyLocator: keychain.KeyLocator{ |
| 1916 | + Family: test.RandInt[keychain.KeyFamily](), |
| 1917 | + Index: uint32(test.RandInt[int32]()), |
| 1918 | + }, |
| 1919 | + }) |
| 1920 | + |
| 1921 | + assetVersionV0 := asset.V0 |
| 1922 | + |
| 1923 | + const numAssets = 1 |
| 1924 | + assetGen := newAssetGenerator(t, numAssets, 1) |
| 1925 | + assetGen.genAssets(t, assetsStore, []assetDesc{ |
| 1926 | + { |
| 1927 | + assetGen: assetGen.assetGens[0], |
| 1928 | + anchorPoint: assetGen.anchorPoints[0], |
| 1929 | + |
| 1930 | + // This is the script key of the asset we'll be |
| 1931 | + // modifying. |
| 1932 | + scriptKey: &targetScriptKey, |
| 1933 | + |
| 1934 | + amt: 16, |
| 1935 | + assetVersion: &assetVersionV0, |
| 1936 | + }, |
| 1937 | + }) |
| 1938 | + |
| 1939 | + // Formulate a spend delta outbound parcel. This parcel will be stored |
| 1940 | + // in the database. We will then manipulate the proof delivery status |
| 1941 | + // of the first transfer output. |
| 1942 | + // |
| 1943 | + // First, we'll generate a new anchor transaction for use in the parcel. |
| 1944 | + newAnchorTx := wire.NewMsgTx(2) |
| 1945 | + newAnchorTx.AddTxIn(&wire.TxIn{}) |
| 1946 | + newAnchorTx.TxIn[0].SignatureScript = []byte{} |
| 1947 | + newAnchorTx.AddTxOut(&wire.TxOut{ |
| 1948 | + PkScript: bytes.Repeat([]byte{0x01}, 34), |
| 1949 | + Value: 1000, |
| 1950 | + }) |
| 1951 | + anchorTxHash := newAnchorTx.TxHash() |
| 1952 | + |
| 1953 | + // Next, we'll generate script keys for the two transfer outputs. |
| 1954 | + newScriptKey := asset.NewScriptKeyBip86(keychain.KeyDescriptor{ |
| 1955 | + PubKey: test.RandPubKey(t), |
| 1956 | + KeyLocator: keychain.KeyLocator{ |
| 1957 | + Index: uint32(rand.Int31()), |
| 1958 | + Family: keychain.KeyFamily(rand.Int31()), |
| 1959 | + }, |
| 1960 | + }) |
| 1961 | + |
| 1962 | + newScriptKey2 := asset.NewScriptKeyBip86(keychain.KeyDescriptor{ |
| 1963 | + PubKey: test.RandPubKey(t), |
| 1964 | + KeyLocator: keychain.KeyLocator{ |
| 1965 | + Index: uint32(rand.Int31()), |
| 1966 | + Family: keychain.KeyFamily(rand.Int31()), |
| 1967 | + }, |
| 1968 | + }) |
| 1969 | + |
| 1970 | + // The outbound parcel will split the asset into two outputs. The first |
| 1971 | + // will have an amount of 9, and the second will have the remainder of |
| 1972 | + // the asset amount. |
| 1973 | + newAmt := 9 |
| 1974 | + |
| 1975 | + senderBlob := bytes.Repeat([]byte{0x01}, 100) |
| 1976 | + receiverBlob := bytes.Repeat([]byte{0x02}, 100) |
| 1977 | + |
| 1978 | + newWitness := asset.Witness{ |
| 1979 | + PrevID: &asset.PrevID{}, |
| 1980 | + TxWitness: [][]byte{{0x01}, {0x02}}, |
| 1981 | + SplitCommitment: nil, |
| 1982 | + } |
| 1983 | + |
| 1984 | + // Mock proof courier address. |
| 1985 | + proofCourierAddrBytes := []byte("universerpc://localhost:10009") |
| 1986 | + |
| 1987 | + // Fetch the asset that was previously generated. |
| 1988 | + allAssets, err := assetsStore.FetchAllAssets(ctx, true, false, nil) |
| 1989 | + require.NoError(t, err) |
| 1990 | + require.Len(t, allAssets, numAssets) |
| 1991 | + |
| 1992 | + inputAsset := allAssets[0] |
| 1993 | + |
| 1994 | + // Construct the outbound parcel that will be stored in the database. |
| 1995 | + spendDelta := &tapfreighter.OutboundParcel{ |
| 1996 | + AnchorTx: newAnchorTx, |
| 1997 | + AnchorTxHeightHint: 1450, |
| 1998 | + ChainFees: int64(100), |
| 1999 | + Inputs: []tapfreighter.TransferInput{{ |
| 2000 | + PrevID: asset.PrevID{ |
| 2001 | + OutPoint: wire.OutPoint{ |
| 2002 | + Hash: assetGen.anchorTxs[0].TxHash(), |
| 2003 | + Index: 0, |
| 2004 | + }, |
| 2005 | + ID: inputAsset.ID(), |
| 2006 | + ScriptKey: asset.ToSerialized( |
| 2007 | + inputAsset.ScriptKey.PubKey, |
| 2008 | + ), |
| 2009 | + }, |
| 2010 | + Amount: inputAsset.Amount, |
| 2011 | + }}, |
| 2012 | + Outputs: []tapfreighter.TransferOutput{{ |
| 2013 | + Anchor: tapfreighter.Anchor{ |
| 2014 | + Value: 1000, |
| 2015 | + OutPoint: wire.OutPoint{ |
| 2016 | + Hash: anchorTxHash, |
| 2017 | + Index: 0, |
| 2018 | + }, |
| 2019 | + InternalKey: keychain.KeyDescriptor{ |
| 2020 | + PubKey: test.RandPubKey(t), |
| 2021 | + KeyLocator: keychain.KeyLocator{ |
| 2022 | + Family: keychain.KeyFamily( |
| 2023 | + rand.Int31(), |
| 2024 | + ), |
| 2025 | + Index: uint32( |
| 2026 | + test.RandInt[int32](), |
| 2027 | + ), |
| 2028 | + }, |
| 2029 | + }, |
| 2030 | + TaprootAssetRoot: bytes.Repeat([]byte{0x1}, 32), |
| 2031 | + MerkleRoot: bytes.Repeat([]byte{0x1}, 32), |
| 2032 | + }, |
| 2033 | + ScriptKey: newScriptKey, |
| 2034 | + ScriptKeyLocal: false, |
| 2035 | + Amount: uint64(newAmt), |
| 2036 | + LockTime: 1337, |
| 2037 | + RelativeLockTime: 31337, |
| 2038 | + WitnessData: []asset.Witness{newWitness}, |
| 2039 | + SplitCommitmentRoot: nil, |
| 2040 | + AssetVersion: asset.V0, |
| 2041 | + ProofSuffix: receiverBlob, |
| 2042 | + ProofCourierAddr: proofCourierAddrBytes, |
| 2043 | + ProofDeliveryComplete: fn.Some[bool](false), |
| 2044 | + Position: 0, |
| 2045 | + }, { |
| 2046 | + Anchor: tapfreighter.Anchor{ |
| 2047 | + Value: 1000, |
| 2048 | + OutPoint: wire.OutPoint{ |
| 2049 | + Hash: anchorTxHash, |
| 2050 | + Index: 1, |
| 2051 | + }, |
| 2052 | + InternalKey: keychain.KeyDescriptor{ |
| 2053 | + PubKey: test.RandPubKey(t), |
| 2054 | + KeyLocator: keychain.KeyLocator{ |
| 2055 | + Family: keychain.KeyFamily( |
| 2056 | + rand.Int31(), |
| 2057 | + ), |
| 2058 | + Index: uint32( |
| 2059 | + test.RandInt[int32](), |
| 2060 | + ), |
| 2061 | + }, |
| 2062 | + }, |
| 2063 | + TaprootAssetRoot: bytes.Repeat([]byte{0x1}, 32), |
| 2064 | + MerkleRoot: bytes.Repeat([]byte{0x1}, 32), |
| 2065 | + }, |
| 2066 | + ScriptKey: newScriptKey2, |
| 2067 | + ScriptKeyLocal: true, |
| 2068 | + Amount: inputAsset.Amount - uint64(newAmt), |
| 2069 | + WitnessData: []asset.Witness{newWitness}, |
| 2070 | + SplitCommitmentRoot: nil, |
| 2071 | + AssetVersion: asset.V1, |
| 2072 | + ProofSuffix: senderBlob, |
| 2073 | + Position: 1, |
| 2074 | + }}, |
| 2075 | + } |
| 2076 | + |
| 2077 | + // Store the outbound parcel in the database. |
| 2078 | + leaseOwner := fn.ToArray[[32]byte](test.RandBytes(32)) |
| 2079 | + leaseExpiry := time.Now().Add(time.Hour) |
| 2080 | + require.NoError(t, assetsStore.LogPendingParcel( |
| 2081 | + ctx, spendDelta, leaseOwner, leaseExpiry, |
| 2082 | + )) |
| 2083 | + |
| 2084 | + // At this point, we should be able to query for the log parcel, by |
| 2085 | + // looking for all unconfirmed transfers. |
| 2086 | + assetTransfers, err := db.QueryAssetTransfers(ctx, TransferQuery{}) |
| 2087 | + require.NoError(t, err) |
| 2088 | + require.Len(t, assetTransfers, 1) |
| 2089 | + |
| 2090 | + // We should also be able to find the transfer outputs. |
| 2091 | + transferOutputs, err := db.FetchTransferOutputs( |
| 2092 | + ctx, assetTransfers[0].ID, |
| 2093 | + ) |
| 2094 | + require.NoError(t, err) |
| 2095 | + require.Len(t, transferOutputs, 2) |
| 2096 | + |
| 2097 | + // Let's confirm that the proof has not been delivered for the first |
| 2098 | + // transfer output and that the proof delivery status for the second |
| 2099 | + // transfer output is still unset. |
| 2100 | + require.Equal( |
| 2101 | + t, sqlBool(false), transferOutputs[0].ProofDeliveryComplete, |
| 2102 | + ) |
| 2103 | + require.Equal( |
| 2104 | + t, sql.NullBool{}, transferOutputs[1].ProofDeliveryComplete, |
| 2105 | + ) |
| 2106 | + |
| 2107 | + // We will now set the status of the transfer output proof to |
| 2108 | + // "delivered". |
| 2109 | + // |
| 2110 | + // nolint: lll |
| 2111 | + err = db.SetTransferOutputProofDeliveryStatus( |
| 2112 | + ctx, OutputProofDeliveryStatus{ |
| 2113 | + DeliveryComplete: sqlBool(true), |
| 2114 | + SerializedAnchorOutpoint: transferOutputs[0].AnchorOutpoint, |
| 2115 | + Position: transferOutputs[0].Position, |
| 2116 | + }, |
| 2117 | + ) |
| 2118 | + require.NoError(t, err) |
| 2119 | + |
| 2120 | + // We will check to ensure that the transfer output proof delivery |
| 2121 | + // status has been updated correctly. |
| 2122 | + transferOutputs, err = db.FetchTransferOutputs( |
| 2123 | + ctx, assetTransfers[0].ID, |
| 2124 | + ) |
| 2125 | + require.NoError(t, err) |
| 2126 | + require.Len(t, transferOutputs, 2) |
| 2127 | + |
| 2128 | + // The proof delivery status of the first output should be set to |
| 2129 | + // delivered (true). |
| 2130 | + require.Equal( |
| 2131 | + t, sqlBool(true), transferOutputs[0].ProofDeliveryComplete, |
| 2132 | + ) |
| 2133 | + |
| 2134 | + // The proof delivery status of the second output should be unset. |
| 2135 | + require.Equal( |
| 2136 | + t, sql.NullBool{}, transferOutputs[1].ProofDeliveryComplete, |
| 2137 | + ) |
| 2138 | +} |
0 commit comments