@@ -2180,3 +2180,204 @@ func TestV2RenewalResolution(t *testing.T) {
2180
2180
})
2181
2181
}
2182
2182
}
2183
+
2184
+ func TestValidateTransactionElements (t * testing.T ) {
2185
+ n , genesisBlock := testnet ()
2186
+ n .InitialTarget = types.BlockID {0xFF }
2187
+ n .HardforkV2 .AllowHeight = 0
2188
+ n .HardforkV2 .RequireHeight = 0
2189
+
2190
+ giftPrivateKey := types .GeneratePrivateKey ()
2191
+ giftPublicKey := giftPrivateKey .PublicKey ()
2192
+ giftPolicy := types .PolicyPublicKey (giftPublicKey )
2193
+ giftAddress := types .StandardAddress (giftPublicKey )
2194
+
2195
+ renterPrivateKey := types .GeneratePrivateKey ()
2196
+ renterPublicKey := renterPrivateKey .PublicKey ()
2197
+ hostPrivateKey := types .GeneratePrivateKey ()
2198
+ hostPublicKey := hostPrivateKey .PublicKey ()
2199
+
2200
+ giftAmountSC := types .Siacoins (100 )
2201
+ giftAmountSF := uint64 (100 )
2202
+ v1GiftFC := prepareContractFormation (renterPublicKey , hostPublicKey , types .Siacoins (1 ), types .Siacoins (1 ), 100 , 100 , types .VoidAddress )
2203
+ v1GiftFC .Filesize = 65
2204
+ v1GiftFC .FileMerkleRoot = blake2b .SumPair ((State {}).StorageProofLeafHash ([]byte {1 }), (State {}).StorageProofLeafHash ([]byte {2 }))
2205
+ v2GiftFC := types.V2FileContract {
2206
+ Capacity : v1GiftFC .Filesize ,
2207
+ Filesize : v1GiftFC .Filesize ,
2208
+ FileMerkleRoot : v1GiftFC .FileMerkleRoot ,
2209
+ ProofHeight : 20 ,
2210
+ ExpirationHeight : 30 ,
2211
+ RenterOutput : v1GiftFC .ValidProofOutputs [0 ],
2212
+ HostOutput : v1GiftFC .ValidProofOutputs [1 ],
2213
+ MissedHostValue : v1GiftFC .MissedProofOutputs [1 ].Value ,
2214
+ TotalCollateral : v1GiftFC .Payout ,
2215
+ RenterPublicKey : renterPublicKey ,
2216
+ HostPublicKey : hostPublicKey ,
2217
+ }
2218
+ contractCost := v2GiftFC .RenterOutput .Value .Add (v2GiftFC .HostOutput .Value ).Add (n .GenesisState ().V2FileContractTax (v2GiftFC ))
2219
+
2220
+ giftTxn := types.V2Transaction {
2221
+ SiacoinOutputs : []types.SiacoinOutput {
2222
+ {Address : giftAddress , Value : giftAmountSC },
2223
+ {Address : giftAddress , Value : contractCost },
2224
+ },
2225
+ SiafundOutputs : []types.SiafundOutput {
2226
+ {Address : giftAddress , Value : giftAmountSF },
2227
+ },
2228
+ FileContracts : []types.V2FileContract {v2GiftFC },
2229
+ }
2230
+
2231
+ genesisBlock .Transactions = nil
2232
+ genesisBlock .V2 = & types.V2BlockData {
2233
+ Transactions : []types.V2Transaction {giftTxn },
2234
+ }
2235
+
2236
+ _ , au := ApplyBlock (n .GenesisState (), genesisBlock , V1BlockSupplement {}, time.Time {})
2237
+ sces := make ([]types.SiacoinElement , len (au .SiacoinElementDiffs ()))
2238
+ for i := range sces {
2239
+ sces [i ] = au .SiacoinElementDiffs ()[i ].SiacoinElement .Copy ()
2240
+ }
2241
+ sfes := make ([]types.SiafundElement , len (au .SiafundElementDiffs ()))
2242
+ for i := range sfes {
2243
+ sfes [i ] = au .SiafundElementDiffs ()[i ].SiafundElement .Copy ()
2244
+ }
2245
+ fces := make ([]types.V2FileContractElement , len (au .V2FileContractElementDiffs ()))
2246
+ for i := range fces {
2247
+ fces [i ] = au .V2FileContractElementDiffs ()[i ].V2FileContractElement .Copy ()
2248
+ }
2249
+ cies := []types.ChainIndexElement {au .ChainIndexElement ()}
2250
+
2251
+ db , cs := newConsensusDB (n , genesisBlock )
2252
+
2253
+ fc := v2GiftFC
2254
+ fc .TotalCollateral = fc .HostOutput .Value
2255
+
2256
+ rev1 := v2GiftFC
2257
+ rev1 .RevisionNumber ++
2258
+ minerFee := types .Siacoins (1 )
2259
+ b := types.Block {
2260
+ ParentID : genesisBlock .ID (),
2261
+ Timestamp : types .CurrentTimestamp (),
2262
+ V2 : & types.V2BlockData {
2263
+ Height : 1 ,
2264
+ Transactions : []types.V2Transaction {{
2265
+ SiacoinInputs : []types.V2SiacoinInput {{
2266
+ Parent : sces [0 ].Copy (),
2267
+ SatisfiedPolicy : types.SatisfiedPolicy {Policy : giftPolicy },
2268
+ }},
2269
+ SiafundInputs : []types.V2SiafundInput {{
2270
+ Parent : sfes [0 ].Copy (),
2271
+ ClaimAddress : types .VoidAddress ,
2272
+ SatisfiedPolicy : types.SatisfiedPolicy {Policy : giftPolicy },
2273
+ }},
2274
+ SiacoinOutputs : []types.SiacoinOutput {
2275
+ {Value : giftAmountSC .Sub (minerFee ).Sub (contractCost ), Address : giftAddress },
2276
+ },
2277
+ SiafundOutputs : []types.SiafundOutput {
2278
+ {Value : giftAmountSF / 2 , Address : giftAddress },
2279
+ {Value : giftAmountSF / 2 , Address : types .VoidAddress },
2280
+ },
2281
+ FileContracts : []types.V2FileContract {fc },
2282
+ FileContractRevisions : []types.V2FileContractRevision {
2283
+ {Parent : au .V2FileContractElementDiffs ()[0 ].V2FileContractElement .Copy (), Revision : rev1 },
2284
+ },
2285
+ MinerFee : minerFee ,
2286
+ }},
2287
+ },
2288
+ MinerPayouts : []types.SiacoinOutput {{
2289
+ Address : types .VoidAddress ,
2290
+ Value : cs .BlockReward ().Add (minerFee ),
2291
+ }},
2292
+ }
2293
+
2294
+ // validate elements
2295
+ txn := b .V2 .Transactions [0 ]
2296
+ if err := cs .Elements .ValidateTransactionElements (txn ); err != nil {
2297
+ t .Fatal (err )
2298
+ }
2299
+ // validate that corrupting an element results in an error
2300
+ for _ , fn := range []func (){
2301
+ func () { txn .SiacoinInputs [0 ].Parent .ID [0 ] ^= 1 },
2302
+ func () { txn .SiafundInputs [0 ].Parent .StateElement .LeafIndex ^= 1 },
2303
+ func () { txn .FileContractRevisions [0 ].Parent .StateElement .MerkleProof [0 ][0 ] ^= 1 },
2304
+ } {
2305
+ fn ()
2306
+ if err := cs .Elements .ValidateTransactionElements (txn ); err == nil || ! strings .Contains (err .Error (), "invalid Merkle proof" ) {
2307
+ t .Fatal ("expected invalid Merkle proof error, got" , err )
2308
+ }
2309
+ fn ()
2310
+ }
2311
+
2312
+ cs , testAU := ApplyBlock (cs , b , db .supplementTipBlock (b ), time .Now ())
2313
+ db .applyBlock (testAU )
2314
+ updateProofs (testAU , sces , sfes , fces , cies )
2315
+
2316
+ testSces := make ([]types.SiacoinElement , len (testAU .SiacoinElementDiffs ()))
2317
+ for i := range testSces {
2318
+ testSces [i ] = testAU .SiacoinElementDiffs ()[i ].SiacoinElement .Copy ()
2319
+ }
2320
+ testSfes := make ([]types.SiafundElement , len (testAU .SiafundElementDiffs ()))
2321
+ for i := range testSfes {
2322
+ testSfes [i ] = testAU .SiafundElementDiffs ()[i ].SiafundElement .Copy ()
2323
+ }
2324
+ testFces := make ([]types.V2FileContractElement , len (testAU .V2FileContractElementDiffs ()))
2325
+ for i := range testFces {
2326
+ testFces [i ] = testAU .V2FileContractElementDiffs ()[i ].V2FileContractElement .Copy ()
2327
+ }
2328
+ cies = append (cies , testAU .ChainIndexElement ())
2329
+
2330
+ // mine empty blocks
2331
+ blockID := b .ID ()
2332
+ for i := uint64 (0 ); i < v2GiftFC .ProofHeight ; i ++ {
2333
+ b := types.Block {
2334
+ ParentID : blockID ,
2335
+ Timestamp : types .CurrentTimestamp (),
2336
+ V2 : & types.V2BlockData {
2337
+ Height : cs .Index .Height + 1 ,
2338
+ },
2339
+ MinerPayouts : []types.SiacoinOutput {{
2340
+ Address : types .VoidAddress ,
2341
+ Value : cs .BlockReward (),
2342
+ }},
2343
+ }
2344
+ b .V2 .Commitment = cs .Commitment (b .MinerPayouts [0 ].Address , b .Transactions , b .V2Transactions ())
2345
+
2346
+ findBlockNonce (cs , & b )
2347
+ if err := ValidateBlock (cs , b , db .supplementTipBlock (b )); err != nil {
2348
+ t .Fatal (err )
2349
+ }
2350
+ cs , au = ApplyBlock (cs , b , db .supplementTipBlock (b ), time .Now ())
2351
+ db .applyBlock (au )
2352
+ updateProofs (au , sces , sfes , fces , cies )
2353
+ updateProofs (au , testSces , testSfes , testFces , nil )
2354
+ cies = append (cies , au .ChainIndexElement ())
2355
+
2356
+ blockID = b .ID ()
2357
+ }
2358
+
2359
+ // construct a transaction that resolves the file contract
2360
+ txn = types.V2Transaction {
2361
+ FileContractResolutions : []types.V2FileContractResolution {{
2362
+ Parent : testFces [0 ].Copy (),
2363
+ Resolution : & types.V2StorageProof {
2364
+ ProofIndex : cies [len (cies )- 2 ].Copy (),
2365
+ Leaf : [64 ]byte {1 },
2366
+ Proof : []types.Hash256 {cs .StorageProofLeafHash ([]byte {2 })},
2367
+ },
2368
+ }},
2369
+ }
2370
+ if err := cs .Elements .ValidateTransactionElements (txn ); err != nil {
2371
+ t .Fatal (err )
2372
+ }
2373
+ for _ , fn := range []func (){
2374
+ func () { txn .FileContractResolutions [0 ].Resolution .(* types.V2StorageProof ).ProofIndex .ID [0 ] ^= 1 },
2375
+ func () { txn .FileContractResolutions [0 ].Parent .StateElement .MerkleProof [0 ][0 ] ^= 1 },
2376
+ } {
2377
+ fn ()
2378
+ if err := cs .Elements .ValidateTransactionElements (txn ); err == nil || ! strings .Contains (err .Error (), "invalid Merkle proof" ) {
2379
+ t .Fatal ("expected invalid Merkle proof error, got" , err )
2380
+ }
2381
+ fn ()
2382
+ }
2383
+ }
0 commit comments