@@ -1850,3 +1850,88 @@ func TestPsbtV2Locktimes(t *testing.T) {
18501850 // Test modifiability flag.
18511851 require .Equal (t , uint8 (0x01 ), p .TxModifiable )
18521852}
1853+
1854+ // TestPSBTv2DetermineLockTimeAlgorithm tests the comprehensive BIP-370 lock time determination algorithm
1855+ func TestPSBTv2DetermineLockTimeAlgorithm (t * testing.T ) {
1856+ t .Run ("Height-based preference when both supported (BIP-370 tie-breaker)" , func (t * testing.T ) {
1857+ p , err := NewV2 (2 , 100000 , 0 )
1858+ require .NoError (t , err )
1859+
1860+ txid , _ := chainhash .NewHashFromStr ("1111111111111111111111111111111111111111111111111111111111111111" )
1861+
1862+ // Input 1: Both time and height (flexible)
1863+ p .AddInput (* wire .NewOutPoint (txid , 0 ), 0 )
1864+ p .Inputs [0 ].TimeLocktime = 1600000000
1865+ p .Inputs [0 ].HeightLocktime = 550000
1866+
1867+ // Input 2: Both time and height (flexible)
1868+ p .AddInput (* wire .NewOutPoint (txid , 1 ), 0 )
1869+ p .Inputs [1 ].TimeLocktime = 1650000000
1870+ p .Inputs [1 ].HeightLocktime = 600000
1871+
1872+ // BIP-370: "height-based must be chosen" when both supported
1873+ lockTime , err := p .DetermineLockTime ()
1874+ require .NoError (t , err )
1875+ require .Equal (t , uint32 (600000 ), lockTime ) // Max height, NOT max time
1876+ })
1877+
1878+ t .Run ("Conflicting requirements should error" , func (t * testing.T ) {
1879+ p , err := NewV2 (2 , 0 , 0 )
1880+ require .NoError (t , err )
1881+
1882+ txid , _ := chainhash .NewHashFromStr ("2222222222222222222222222222222222222222222222222222222222222222" )
1883+
1884+ // Input 1: Time-only (cannot satisfy height)
1885+ p .AddInput (* wire .NewOutPoint (txid , 0 ), 0 )
1886+ p .Inputs [0 ].TimeLocktime = 1600000000
1887+
1888+ // Input 2: Height-only (cannot satisfy time)
1889+ p .AddInput (* wire .NewOutPoint (txid , 1 ), 0 )
1890+ p .Inputs [1 ].HeightLocktime = 500000
1891+
1892+ // Should fail - conflicting requirements
1893+ _ , err = p .DetermineLockTime ()
1894+ require .Error (t , err )
1895+ require .Equal (t , ErrInvalidPsbtFormat , err )
1896+ })
1897+
1898+ t .Run ("Fallback locktime when no constraints" , func (t * testing.T ) {
1899+ fallback := uint32 (123456 )
1900+ p , err := NewV2 (2 , fallback , 0 )
1901+ require .NoError (t , err )
1902+
1903+ txid , _ := chainhash .NewHashFromStr ("3333333333333333333333333333333333333333333333333333333333333333" )
1904+ p .AddInput (* wire .NewOutPoint (txid , 0 ), 0 )
1905+ // No TimeLocktime or HeightLocktime set
1906+
1907+ lockTime , err := p .DetermineLockTime ()
1908+ require .NoError (t , err )
1909+ require .Equal (t , fallback , lockTime )
1910+ })
1911+ }
1912+
1913+ // TestPSBTv2AddUnknownFields tests the addUnknown field handling
1914+ func TestPSBTv2AddUnknownFields (t * testing.T ) {
1915+ p , err := NewV2 (2 , 0 , 0 )
1916+ require .NoError (t , err )
1917+
1918+ txid , _ := chainhash .NewHashFromStr ("4444444444444444444444444444444444444444444444444444444444444444" )
1919+ p .AddInput (* wire .NewOutPoint (txid , 0 ), 0 )
1920+
1921+ // Test adding unknown field succeeds
1922+ err = p .Inputs [0 ].addUnknown (0xfc , []byte {0x01 , 0x02 }, []byte {0x03 , 0x04 })
1923+ require .NoError (t , err )
1924+ require .Len (t , p .Inputs [0 ].Unknowns , 1 )
1925+
1926+ // Test duplicate detection
1927+ err = p .Inputs [0 ].addUnknown (0xfc , []byte {0x01 , 0x02 }, []byte {0x03 , 0x04 })
1928+ require .Error (t , err )
1929+ require .Equal (t , ErrDuplicateKey , err )
1930+
1931+ p .AddOutput (1000000 , []byte {0x76 , 0xa9 , 0x14 })
1932+
1933+ // Test output unknown fields
1934+ err = p .Outputs [0 ].addUnknown (0xfd , []byte {0x05 }, []byte {0x06 })
1935+ require .NoError (t , err )
1936+ require .Len (t , p .Outputs [0 ].Unknowns , 1 )
1937+ }
0 commit comments