github.com/filecoin-project/specs-actors/v4@v4.0.2/support/mock/mockrt.go (about) 1 package mock 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "reflect" 8 goruntime "runtime" 9 "runtime/debug" 10 "strings" 11 "testing" 12 13 addr "github.com/filecoin-project/go-address" 14 "github.com/filecoin-project/go-state-types/abi" 15 "github.com/filecoin-project/go-state-types/big" 16 "github.com/filecoin-project/go-state-types/cbor" 17 "github.com/filecoin-project/go-state-types/crypto" 18 "github.com/filecoin-project/go-state-types/exitcode" 19 "github.com/filecoin-project/go-state-types/network" 20 "github.com/filecoin-project/go-state-types/rt" 21 cid "github.com/ipfs/go-cid" 22 mh "github.com/multiformats/go-multihash" 23 24 "github.com/filecoin-project/specs-actors/v4/actors/builtin" 25 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported" 26 "github.com/filecoin-project/specs-actors/v4/actors/runtime" 27 "github.com/filecoin-project/specs-actors/v4/actors/runtime/proof" 28 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 29 "github.com/filecoin-project/specs-actors/v4/support/ipld" 30 ) 31 32 // A mock runtime for unit testing of actors in isolation. 33 // The mock allows direct specification of the runtime context as observable by an actor, supports 34 // the storage interface, and mocks out side-effect-inducing calls. 35 type Runtime struct { 36 // Execution context 37 ctx context.Context 38 epoch abi.ChainEpoch 39 networkVersion network.Version 40 receiver addr.Address 41 caller addr.Address 42 callerType cid.Cid 43 miner addr.Address 44 valueReceived abi.TokenAmount 45 idAddresses map[addr.Address]addr.Address 46 actorCodeCIDs map[addr.Address]cid.Cid 47 newActorAddr addr.Address 48 circulatingSupply abi.TokenAmount 49 50 // Actor state 51 state cid.Cid 52 balance abi.TokenAmount 53 54 // VM implementation 55 store map[cid.Cid][]byte 56 inCall bool 57 inTransaction bool 58 // Maps (references to) loaded state objs to their expected cid. 59 // Used for detecting modifications to state outside of transactions. 60 stateUsedObjs map[cbor.Marshaler]cid.Cid 61 // Syscalls 62 hashfunc func(data []byte) [32]byte 63 64 // Expectations 65 t testing.TB 66 expectValidateCallerAny bool 67 expectValidateCallerAddr []addr.Address 68 expectValidateCallerType []cid.Cid 69 expectRandomnessBeacon []*expectRandomness 70 expectRandomnessTickets []*expectRandomness 71 expectSends []*expectedMessage 72 expectVerifySigs []*expectVerifySig 73 expectCreateActor *expectCreateActor 74 expectVerifySeal *expectVerifySeal 75 expectComputeUnsealedSectorCID *expectComputeUnsealedSectorCID 76 expectVerifyPoSt *expectVerifyPoSt 77 expectVerifyConsensusFault *expectVerifyConsensusFault 78 expectDeleteActor *addr.Address 79 expectBatchVerifySeals *expectBatchVerifySeals 80 81 logs []string 82 // Gas charged explicitly through rt.ChargeGas. Note: most charges are implicit 83 gasCharged int64 84 } 85 86 type expectBatchVerifySeals struct { 87 in map[addr.Address][]proof.SealVerifyInfo 88 out map[addr.Address][]bool 89 err error 90 } 91 92 type expectRandomness struct { 93 // Expected parameters. 94 tag crypto.DomainSeparationTag 95 epoch abi.ChainEpoch 96 entropy []byte 97 // Result. 98 out abi.Randomness 99 } 100 101 type expectedMessage struct { 102 // expectedMessage values 103 to addr.Address 104 method abi.MethodNum 105 params cbor.Marshaler 106 value abi.TokenAmount 107 108 // returns from applying expectedMessage 109 sendReturn cbor.Er 110 exitCode exitcode.ExitCode 111 } 112 113 type expectVerifySig struct { 114 // Expected arguments 115 sig crypto.Signature 116 signer addr.Address 117 plaintext []byte 118 // Result 119 result error 120 } 121 122 type expectVerifySeal struct { 123 seal proof.SealVerifyInfo 124 result error 125 } 126 127 type expectComputeUnsealedSectorCID struct { 128 reg abi.RegisteredSealProof 129 pieces []abi.PieceInfo 130 cid cid.Cid 131 resultErr error 132 } 133 134 type expectVerifyPoSt struct { 135 post proof.WindowPoStVerifyInfo 136 result error 137 } 138 139 func (m *expectedMessage) Equal(to addr.Address, method abi.MethodNum, params cbor.Marshaler, value abi.TokenAmount) bool { 140 // avoid nil vs. zero/empty discrepancies that would disappear in serialization 141 paramBuf1 := new(bytes.Buffer) 142 if m.params != nil { 143 m.params.MarshalCBOR(paramBuf1) // nolint: errcheck 144 } 145 paramBuf2 := new(bytes.Buffer) 146 if params != nil { 147 params.MarshalCBOR(paramBuf2) // nolint: errcheck 148 } 149 150 return m.to == to && m.method == method && m.value.Equals(value) && bytes.Equal(paramBuf1.Bytes(), paramBuf2.Bytes()) 151 } 152 153 func (m *expectedMessage) String() string { 154 return fmt.Sprintf("to: %v method: %v value: %v params: %v sendReturn: %v exitCode: %v", m.to, m.method, m.value, m.params, m.sendReturn, m.exitCode) 155 } 156 157 type expectCreateActor struct { 158 // Expected parameters 159 codeId cid.Cid 160 address addr.Address 161 } 162 163 type expectVerifyConsensusFault struct { 164 requireCorrectInput bool 165 BlockHeader1 []byte 166 BlockHeader2 []byte 167 BlockHeaderExtra []byte 168 169 Fault *runtime.ConsensusFault 170 Err error 171 } 172 173 var _ runtime.Runtime = &Runtime{} 174 var _ runtime.StateHandle = &Runtime{} 175 var typeOfRuntimeInterface = reflect.TypeOf((*runtime.Runtime)(nil)).Elem() 176 var typeOfCborUnmarshaler = reflect.TypeOf((*cbor.Unmarshaler)(nil)).Elem() 177 var typeOfCborMarshaler = reflect.TypeOf((*cbor.Marshaler)(nil)).Elem() 178 179 ///// Implementation of the runtime API ///// 180 181 func (rt *Runtime) NetworkVersion() network.Version { 182 return rt.networkVersion 183 } 184 185 func (rt *Runtime) CurrEpoch() abi.ChainEpoch { 186 rt.requireInCall() 187 return rt.epoch 188 } 189 190 func (rt *Runtime) ValidateImmediateCallerAcceptAny() { 191 rt.requireInCall() 192 if !rt.expectValidateCallerAny { 193 rt.failTest("unexpected validate-caller-any") 194 } 195 rt.expectValidateCallerAny = false 196 } 197 198 func (rt *Runtime) ValidateImmediateCallerIs(addrs ...addr.Address) { 199 rt.requireInCall() 200 rt.checkArgument(len(addrs) > 0, "addrs must be non-empty") 201 // Check and clear expectations. 202 if len(rt.expectValidateCallerAddr) == 0 { 203 rt.failTest("unexpected validate caller addrs") 204 return 205 } 206 if !reflect.DeepEqual(rt.expectValidateCallerAddr, addrs) { 207 rt.failTest("unexpected validate caller addrs %v, expected %+v", addrs, rt.expectValidateCallerAddr) 208 return 209 } 210 defer func() { 211 rt.expectValidateCallerAddr = nil 212 }() 213 214 // Implement method. 215 for _, expected := range addrs { 216 if rt.caller == expected { 217 return 218 } 219 } 220 rt.Abortf(exitcode.SysErrForbidden, "caller address %v forbidden, allowed: %v", rt.caller, addrs) 221 } 222 223 func (rt *Runtime) ValidateImmediateCallerType(types ...cid.Cid) { 224 rt.requireInCall() 225 rt.checkArgument(len(types) > 0, "types must be non-empty") 226 227 // Check and clear expectations. 228 if len(rt.expectValidateCallerType) == 0 { 229 rt.failTest("unexpected validate caller code") 230 } 231 if !reflect.DeepEqual(rt.expectValidateCallerType, types) { 232 rt.failTest("unexpected validate caller code %v, expected %+v", types, rt.expectValidateCallerType) 233 } 234 defer func() { 235 rt.expectValidateCallerType = nil 236 }() 237 238 // Implement method. 239 for _, expected := range types { 240 if rt.callerType.Equals(expected) { 241 return 242 } 243 } 244 rt.Abortf(exitcode.SysErrForbidden, "caller type %v forbidden, allowed: %v", rt.callerType, types) 245 } 246 247 func (rt *Runtime) CurrentBalance() abi.TokenAmount { 248 rt.requireInCall() 249 return rt.balance 250 } 251 252 func (rt *Runtime) ResolveAddress(address addr.Address) (ret addr.Address, ok bool) { 253 rt.requireInCall() 254 if address.Protocol() == addr.ID { 255 return address, true 256 } 257 resolved, ok := rt.idAddresses[address] 258 return resolved, ok 259 } 260 261 func (rt *Runtime) GetIdAddr(raw addr.Address) (addr.Address, bool) { 262 if raw.Protocol() == addr.ID { 263 return raw, true 264 } 265 a, found := rt.idAddresses[raw] 266 return a, found 267 } 268 269 func (rt *Runtime) GetActorCodeCID(addr addr.Address) (ret cid.Cid, ok bool) { 270 rt.requireInCall() 271 ret, ok = rt.actorCodeCIDs[addr] 272 return 273 } 274 275 func (rt *Runtime) GetRandomnessFromBeacon(tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte) abi.Randomness { 276 rt.requireInCall() 277 if len(rt.expectRandomnessBeacon) == 0 { 278 rt.failTestNow("unexpected call to get randomness for tag %v, epoch %v", tag, epoch) 279 } 280 281 if epoch > rt.epoch { 282 rt.failTestNow("attempt to get randomness from future\n"+ 283 " requested epoch: %d greater than current epoch %d\n", epoch, rt.epoch) 284 } 285 286 exp := rt.expectRandomnessBeacon[0] 287 if tag != exp.tag || epoch != exp.epoch || !bytes.Equal(entropy, exp.entropy) { 288 rt.failTest("unexpected get randomness\n"+ 289 " tag: %d, epoch: %d, entropy: %v\n"+ 290 "expected tag: %d, epoch: %d, entropy: %v", tag, epoch, entropy, exp.tag, exp.epoch, exp.entropy) 291 } 292 defer func() { 293 rt.expectRandomnessBeacon = rt.expectRandomnessBeacon[1:] 294 }() 295 return exp.out 296 } 297 298 func (rt *Runtime) GetRandomnessFromTickets(tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte) abi.Randomness { 299 rt.requireInCall() 300 if len(rt.expectRandomnessTickets) == 0 { 301 rt.failTestNow("unexpected call to get randomness for tag %v, epoch %v", tag, epoch) 302 } 303 304 if epoch > rt.epoch { 305 rt.failTestNow("attempt to get randomness from future\n"+ 306 " requested epoch: %d greater than current epoch %d\n", epoch, rt.epoch) 307 } 308 309 exp := rt.expectRandomnessTickets[0] 310 if tag != exp.tag || epoch != exp.epoch || !bytes.Equal(entropy, exp.entropy) { 311 rt.failTest("unexpected get randomness\n"+ 312 " tag: %d, epoch: %d, entropy: %v\n"+ 313 "expected tag: %d, epoch: %d, entropy: %v", tag, epoch, entropy, exp.tag, exp.epoch, exp.entropy) 314 } 315 defer func() { 316 rt.expectRandomnessTickets = rt.expectRandomnessTickets[1:] 317 }() 318 return exp.out 319 } 320 321 func (rt *Runtime) Send(toAddr addr.Address, methodNum abi.MethodNum, params cbor.Marshaler, value abi.TokenAmount, out cbor.Er) exitcode.ExitCode { 322 rt.requireInCall() 323 if rt.inTransaction { 324 rt.Abortf(exitcode.SysErrorIllegalActor, "side-effect within transaction") 325 } 326 if len(rt.expectSends) == 0 { 327 rt.failTestNow("unexpected send to: %v method: %v, value: %v, params: %v", toAddr, methodNum, value, params) 328 } 329 exp := rt.expectSends[0] 330 331 if !exp.Equal(toAddr, methodNum, params, value) { 332 toName := "unknown" 333 toMeth := "unknown" 334 expToName := "unknown" 335 expToMeth := "unknown" 336 if code, ok := rt.GetActorCodeCID(toAddr); ok && builtin.IsBuiltinActor(code) { 337 toName = builtin.ActorNameByCode(code) 338 toMeth = getMethodName(code, methodNum) 339 } 340 if code, ok := rt.GetActorCodeCID(exp.to); ok && builtin.IsBuiltinActor(code) { 341 expToName = builtin.ActorNameByCode(code) 342 expToMeth = getMethodName(code, exp.method) 343 } 344 345 rt.failTestNow("unexpected send\n"+ 346 " to: %s (%s) method: %d (%s) value: %v params: %v\n"+ 347 "Expected to: %s (%s) method: %d (%s) value: %v params: %v", 348 toAddr, toName, methodNum, toMeth, value, params, exp.to, expToName, exp.method, expToMeth, exp.value, exp.params) 349 } 350 351 if value.GreaterThan(rt.balance) { 352 rt.Abortf(exitcode.SysErrSenderStateInvalid, "cannot send value: %v exceeds balance: %v", value, rt.balance) 353 } 354 355 // pop the expectedMessage from the queue and modify the mockrt balance to reflect the send. 356 defer func() { 357 rt.expectSends = rt.expectSends[1:] 358 rt.balance = big.Sub(rt.balance, value) 359 }() 360 361 // populate the output argument 362 var buf bytes.Buffer 363 err := exp.sendReturn.MarshalCBOR(&buf) 364 if err != nil { 365 rt.failTestNow("error serializing expected send return: %v", err) 366 } 367 err = out.UnmarshalCBOR(&buf) 368 if err != nil { 369 rt.failTestNow("error deserializing send return bytes to output param: %v", err) 370 } 371 372 return exp.exitCode 373 } 374 375 func (rt *Runtime) NewActorAddress() addr.Address { 376 rt.requireInCall() 377 if rt.newActorAddr == addr.Undef { 378 rt.failTestNow("unexpected call to new actor address") 379 } 380 defer func() { rt.newActorAddr = addr.Undef }() 381 return rt.newActorAddr 382 } 383 384 func (rt *Runtime) CreateActor(codeId cid.Cid, address addr.Address) { 385 rt.requireInCall() 386 if rt.inTransaction { 387 rt.Abortf(exitcode.SysErrorIllegalActor, "side-effect within transaction") 388 } 389 exp := rt.expectCreateActor 390 if exp != nil { 391 if !exp.codeId.Equals(codeId) || exp.address != address { 392 rt.failTest("unexpected create actor, code: %s, address: %s; expected code: %s, address: %s", 393 codeId, address, exp.codeId, exp.address) 394 } 395 defer func() { 396 rt.expectCreateActor = nil 397 }() 398 return 399 } 400 rt.failTestNow("unexpected call to create actor") 401 } 402 403 func (rt *Runtime) DeleteActor(addr addr.Address) { 404 rt.requireInCall() 405 if rt.inTransaction { 406 rt.Abortf(exitcode.SysErrorIllegalActor, "side-effect within transaction") 407 } 408 if rt.expectDeleteActor == nil { 409 rt.failTestNow("unexpected call to delete actor %s", addr.String()) 410 } 411 412 if *rt.expectDeleteActor != addr { 413 rt.failTestNow("attempt to delete wrong actor. Expected %s, got %s.", rt.expectDeleteActor.String(), addr.String()) 414 } 415 rt.expectDeleteActor = nil 416 } 417 418 func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { 419 return rt.circulatingSupply 420 } 421 422 func (rt *Runtime) Abortf(errExitCode exitcode.ExitCode, msg string, args ...interface{}) { 423 rt.requireInCall() 424 rt.t.Logf("Mock Runtime Abort ExitCode: %v Reason: %s", errExitCode, fmt.Sprintf(msg, args...)) 425 panic(abort{errExitCode, fmt.Sprintf(msg, args...)}) 426 } 427 428 func (rt *Runtime) Context() context.Context { 429 // requireInCall omitted because it makes using this mock runtime as a store awkward. 430 return rt.ctx 431 } 432 433 func (rt *Runtime) StartSpan(_ string) func() { 434 rt.requireInCall() 435 return func() {} 436 } 437 438 func (rt *Runtime) checkArgument(predicate bool, msg string, args ...interface{}) { 439 if !predicate { 440 rt.Abortf(exitcode.SysErrorIllegalArgument, msg, args...) 441 } 442 } 443 444 ///// Store implementation ///// 445 446 // Gets raw data from the state. This function will extract inline data from the 447 // CID to better mimic what filecoin implementations should do. 448 func (rt *Runtime) get(c cid.Cid) ([]byte, bool) { 449 prefix := c.Prefix() 450 if prefix.Codec != cid.DagCBOR { 451 rt.Abortf(exitcode.ErrSerialization, "tried to fetch a non-cbor object: %s", c) 452 } 453 454 var data []byte 455 if prefix.MhType == mh.IDENTITY { 456 decoded, err := mh.Decode(c.Hash()) 457 if err != nil { 458 rt.Abortf(exitcode.ErrSerialization, "failed to parse identity cid %s: %s", c, err) 459 } 460 data = decoded.Digest 461 } else if stored, found := rt.store[c]; found { 462 data = stored 463 } else { 464 return nil, false 465 } 466 return data, true 467 } 468 469 // Puts raw data into the state, but only if it's not "inlined" into the CID. 470 func (rt *Runtime) put(c cid.Cid, data []byte) { 471 if c.Prefix().MhType != mh.IDENTITY { 472 rt.store[c] = data 473 } 474 } 475 476 func (rt *Runtime) StoreGet(c cid.Cid, o cbor.Unmarshaler) bool { 477 // requireInCall omitted because it makes using this mock runtime as a store awkward. 478 data, found := rt.get(c) 479 if found { 480 err := o.UnmarshalCBOR(bytes.NewReader(data)) 481 if err != nil { 482 rt.Abortf(exitcode.ErrSerialization, err.Error()) 483 } 484 } 485 486 return found 487 } 488 489 func (rt *Runtime) StorePut(o cbor.Marshaler) cid.Cid { 490 // requireInCall omitted because it makes using this mock runtime as a store awkward. 491 key, data, err := ipld.MarshalCBOR(o) 492 if err != nil { 493 rt.Abortf(exitcode.ErrSerialization, err.Error()) 494 } 495 rt.put(key, data) 496 return key 497 } 498 499 ///// Message implementation ///// 500 501 func (rt *Runtime) BlockMiner() addr.Address { 502 return rt.miner 503 } 504 505 func (rt *Runtime) Caller() addr.Address { 506 return rt.caller 507 } 508 509 func (rt *Runtime) Receiver() addr.Address { 510 return rt.receiver 511 } 512 513 func (rt *Runtime) ValueReceived() abi.TokenAmount { 514 return rt.valueReceived 515 } 516 517 ///// State handle implementation ///// 518 519 func (rt *Runtime) StateCreate(obj cbor.Marshaler) { 520 if rt.state.Defined() { 521 rt.Abortf(exitcode.SysErrorIllegalActor, "state already constructed") 522 } 523 rt.state = rt.StorePut(obj) 524 // Track the expected CID of the object. 525 rt.stateUsedObjs[obj] = rt.state 526 } 527 528 func (rt *Runtime) StateReadonly(st cbor.Unmarshaler) { 529 found := rt.StoreGet(rt.state, st) 530 if !found { 531 panic(fmt.Sprintf("actor state not found: %v", rt.state)) 532 } 533 // Track the expected CID of the object. 534 rt.stateUsedObjs[st.(cbor.Marshaler)] = rt.state 535 } 536 537 func (rt *Runtime) StateTransaction(st cbor.Er, f func()) { 538 if rt.inTransaction { 539 rt.Abortf(exitcode.SysErrorIllegalActor, "nested transaction") 540 } 541 rt.checkStateObjectsUnmodified() 542 rt.StateReadonly(st) 543 rt.inTransaction = true 544 defer func() { rt.inTransaction = false }() 545 f() 546 rt.state = rt.StorePut(st) 547 // Track the expected CID of the object. 548 rt.stateUsedObjs[st] = rt.state 549 } 550 551 ///// Syscalls implementation ///// 552 553 func (rt *Runtime) VerifySignature(sig crypto.Signature, signer addr.Address, plaintext []byte) error { 554 if len(rt.expectVerifySigs) == 0 { 555 rt.failTest("unexpected signature verification sig: %v, signer: %s, plaintext: %v", sig, signer, plaintext) 556 } 557 558 exp := rt.expectVerifySigs[0] 559 if exp != nil { 560 if !exp.sig.Equals(&sig) || exp.signer != signer || !bytes.Equal(exp.plaintext, plaintext) { 561 rt.failTest("unexpected signature verification\n"+ 562 " sig: %v, signer: %s, plaintext: %v\n"+ 563 "expected sig: %v, signer: %s, plaintext: %v", 564 sig, signer, plaintext, exp.sig, exp.signer, exp.plaintext) 565 } 566 defer func() { 567 rt.expectVerifySigs = rt.expectVerifySigs[1:] 568 }() 569 return exp.result 570 } 571 rt.failTestNow("unexpected syscall to verify signature %v, signer %s, plaintext %v", sig, signer, plaintext) 572 return nil 573 } 574 575 func (rt *Runtime) HashBlake2b(data []byte) [32]byte { 576 return rt.hashfunc(data) 577 } 578 579 func (rt *Runtime) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) { 580 exp := rt.expectComputeUnsealedSectorCID 581 if exp != nil { 582 if !reflect.DeepEqual(exp.reg, reg) { 583 rt.failTest("unexpected ComputeUnsealedSectorCID proof, expected: %v, got: %v", exp.reg, reg) 584 } 585 if !reflect.DeepEqual(exp.pieces, pieces) { 586 rt.failTest("unexpected ComputeUnsealedSectorCID pieces, expected: %v, got: %v", exp.pieces, pieces) 587 } 588 589 defer func() { 590 rt.expectComputeUnsealedSectorCID = nil 591 }() 592 return exp.cid, exp.resultErr 593 } 594 rt.failTestNow("unexpected syscall to ComputeUnsealedSectorCID %v", reg) 595 return cid.Cid{}, nil 596 } 597 598 func (rt *Runtime) VerifySeal(seal proof.SealVerifyInfo) error { 599 exp := rt.expectVerifySeal 600 if exp != nil { 601 if !reflect.DeepEqual(exp.seal, seal) { 602 rt.failTest("unexpected seal verification\n"+ 603 " : %v\n"+ 604 "expected: %v", 605 seal, exp.seal) 606 } 607 defer func() { 608 rt.expectVerifySeal = nil 609 }() 610 return exp.result 611 } 612 rt.failTestNow("unexpected syscall to verify seal %v", seal) 613 return nil 614 } 615 616 func (rt *Runtime) ExpectBatchVerifySeals(in map[addr.Address][]proof.SealVerifyInfo, out map[addr.Address][]bool, err error) { 617 rt.expectBatchVerifySeals = &expectBatchVerifySeals{ 618 in, out, err, 619 } 620 } 621 622 func (rt *Runtime) BatchVerifySeals(vis map[addr.Address][]proof.SealVerifyInfo) (map[addr.Address][]bool, error) { 623 exp := rt.expectBatchVerifySeals 624 if exp != nil { 625 if len(vis) != len(exp.in) { 626 rt.failTest("length mismatch, expected: %v, actual: %v", exp.in, vis) 627 } 628 629 for key, value := range exp.in { //nolint:nomaprange 630 v, ok := vis[key] 631 if !ok { 632 rt.failTest("address %v expected but not found", key) 633 } 634 635 if len(v) != len(value) { 636 rt.failTest("sector info length mismatch for address %v, \n expected: %v, \n actual: %v", key, value, v) 637 } 638 for i, info := range value { 639 if v[i].SealedCID != info.SealedCID { 640 rt.failTest("sealed cid does not match for address %v", key) 641 } 642 643 if v[i].UnsealedCID != info.UnsealedCID { 644 rt.failTest("unsealed cid does not match for address %v", key) 645 } 646 } 647 648 delete(exp.in, key) 649 } 650 651 if len(exp.in) != 0 { 652 rt.failTest("addresses in expected map absent in actual: %v", exp.in) 653 } 654 defer func() { 655 rt.expectBatchVerifySeals = nil 656 }() 657 return exp.out, exp.err 658 } 659 rt.failTestNow("unexpected syscall to batch verify seals with %v", vis) 660 return nil, nil 661 } 662 663 func (rt *Runtime) VerifyPoSt(vi proof.WindowPoStVerifyInfo) error { 664 exp := rt.expectVerifyPoSt 665 if exp != nil { 666 if !reflect.DeepEqual(exp.post, vi) { 667 rt.failTest("unexpected PoSt verification\n"+ 668 " : %v\n"+ 669 "expected: %v", 670 vi, exp.post) 671 } 672 defer func() { 673 rt.expectVerifyPoSt = nil 674 }() 675 return exp.result 676 } 677 rt.failTestNow("unexpected syscall to verify PoSt %v", vi) 678 return nil 679 } 680 681 func (rt *Runtime) VerifyConsensusFault(h1, h2, extra []byte) (*runtime.ConsensusFault, error) { 682 if rt.expectVerifyConsensusFault == nil { 683 rt.failTestNow("Unexpected syscall VerifyConsensusFault") 684 return nil, nil 685 } 686 687 if rt.expectVerifyConsensusFault.requireCorrectInput { 688 if !bytes.Equal(h1, rt.expectVerifyConsensusFault.BlockHeader1) { 689 rt.failTest("block header 1 does not equal expected block header 1 (%v != %v)", h1, rt.expectVerifyConsensusFault.BlockHeader1) 690 } 691 if !bytes.Equal(h2, rt.expectVerifyConsensusFault.BlockHeader2) { 692 rt.failTest("block header 2 does not equal expected block header 2 (%v != %v)", h2, rt.expectVerifyConsensusFault.BlockHeader2) 693 } 694 if !bytes.Equal(extra, rt.expectVerifyConsensusFault.BlockHeaderExtra) { 695 rt.failTest("block header extra does not equal expected block header extra (%v != %v)", extra, rt.expectVerifyConsensusFault.BlockHeaderExtra) 696 } 697 } 698 699 fault := rt.expectVerifyConsensusFault.Fault 700 err := rt.expectVerifyConsensusFault.Err 701 rt.expectVerifyConsensusFault = nil 702 return fault, err 703 } 704 705 func (rt *Runtime) Log(level rt.LogLevel, msg string, args ...interface{}) { 706 rt.logs = append(rt.logs, fmt.Sprintf(msg, args...)) 707 } 708 709 ///// Trace span implementation ///// 710 711 type TraceSpan struct { 712 } 713 714 func (t TraceSpan) End() { 715 // no-op 716 } 717 718 type abort struct { 719 code exitcode.ExitCode 720 msg string 721 } 722 723 func (a abort) String() string { 724 return fmt.Sprintf("abort(%v): %s", a.code, a.msg) 725 } 726 727 ///// Inspection facilities ///// 728 729 func (rt *Runtime) AdtStore() adt.Store { 730 return adt.AsStore(rt) 731 } 732 733 func (rt *Runtime) StateRoot() cid.Cid { 734 return rt.state 735 } 736 737 func (rt *Runtime) GetState(o cbor.Unmarshaler) { 738 data, found := rt.get(rt.state) 739 if !found { 740 rt.failTestNow("can't find state at root %v", rt.state) // something internal is messed up 741 } 742 err := o.UnmarshalCBOR(bytes.NewReader(data)) 743 if err != nil { 744 rt.failTestNow("error loading state: %v", err) 745 } 746 } 747 748 func (rt *Runtime) Balance() abi.TokenAmount { 749 return rt.balance 750 } 751 752 func (rt *Runtime) Epoch() abi.ChainEpoch { 753 return rt.epoch 754 } 755 756 ///// Mocking facilities ///// 757 758 func (rt *Runtime) SetCaller(address addr.Address, actorType cid.Cid) { 759 rt.caller = address 760 rt.callerType = actorType 761 rt.actorCodeCIDs[address] = actorType 762 } 763 764 func (rt *Runtime) SetAddressActorType(address addr.Address, actorType cid.Cid) { 765 rt.actorCodeCIDs[address] = actorType 766 } 767 768 func (rt *Runtime) SetBalance(amt abi.TokenAmount) { 769 rt.balance = amt 770 } 771 772 func (rt *Runtime) SetReceived(amt abi.TokenAmount) { 773 rt.valueReceived = amt 774 } 775 776 func (rt *Runtime) SetNetworkVersion(v network.Version) { 777 rt.networkVersion = v 778 } 779 780 func (rt *Runtime) SetEpoch(epoch abi.ChainEpoch) { 781 rt.epoch = epoch 782 } 783 784 func (rt *Runtime) ReplaceState(o cbor.Marshaler) { 785 rt.state = rt.StorePut(o) 786 } 787 788 func (rt *Runtime) SetCirculatingSupply(amt abi.TokenAmount) { 789 rt.circulatingSupply = amt 790 } 791 792 func (rt *Runtime) AddIDAddress(src addr.Address, target addr.Address) { 793 rt.require(target.Protocol() == addr.ID, "target must use ID address protocol") 794 rt.idAddresses[src] = target 795 } 796 797 func (rt *Runtime) SetNewActorAddress(actAddr addr.Address) { 798 rt.require(actAddr.Protocol() == addr.Actor, "new actor address must be protocol: Actor, got protocol: %v", actAddr.Protocol()) 799 rt.newActorAddr = actAddr 800 } 801 802 func (rt *Runtime) ExpectValidateCallerAny() { 803 rt.expectValidateCallerAny = true 804 } 805 806 func (rt *Runtime) ExpectValidateCallerAddr(addrs ...addr.Address) { 807 rt.require(len(addrs) > 0, "addrs must be non-empty") 808 rt.expectValidateCallerAddr = addrs[:] 809 } 810 811 func (rt *Runtime) ExpectValidateCallerType(types ...cid.Cid) { 812 rt.require(len(types) > 0, "types must be non-empty") 813 rt.expectValidateCallerType = types[:] 814 } 815 816 func (rt *Runtime) ExpectGetRandomnessBeacon(tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte, out abi.Randomness) { 817 rt.expectRandomnessBeacon = append(rt.expectRandomnessBeacon, &expectRandomness{ 818 tag: tag, 819 epoch: epoch, 820 entropy: entropy, 821 out: out, 822 }) 823 } 824 825 func (rt *Runtime) ExpectGetRandomnessTickets(tag crypto.DomainSeparationTag, epoch abi.ChainEpoch, entropy []byte, out abi.Randomness) { 826 rt.expectRandomnessTickets = append(rt.expectRandomnessTickets, &expectRandomness{ 827 tag: tag, 828 epoch: epoch, 829 entropy: entropy, 830 out: out, 831 }) 832 } 833 834 func (rt *Runtime) ExpectSend(toAddr addr.Address, methodNum abi.MethodNum, params cbor.Marshaler, value abi.TokenAmount, ret cbor.Er, exitCode exitcode.ExitCode) { 835 // Adapt nil to Empty as convenience for the caller (otherwise we would require non-nil here). 836 if ret == nil { 837 ret = abi.Empty 838 } 839 rt.expectSends = append(rt.expectSends, &expectedMessage{ 840 to: toAddr, 841 method: methodNum, 842 params: params, 843 value: value, 844 sendReturn: ret, 845 exitCode: exitCode, 846 }) 847 } 848 849 func (rt *Runtime) ExpectVerifySignature(sig crypto.Signature, signer addr.Address, plaintext []byte, result error) { 850 rt.expectVerifySigs = append(rt.expectVerifySigs, &expectVerifySig{ 851 sig: sig, 852 signer: signer, 853 plaintext: plaintext, 854 result: result, 855 }) 856 } 857 858 func (rt *Runtime) ExpectCreateActor(codeId cid.Cid, address addr.Address) { 859 rt.expectCreateActor = &expectCreateActor{ 860 codeId: codeId, 861 address: address, 862 } 863 } 864 865 func (rt *Runtime) ExpectDeleteActor(beneficiary addr.Address) { 866 rt.expectDeleteActor = &beneficiary 867 } 868 869 func (rt *Runtime) SetHasher(f func(data []byte) [32]byte) { 870 rt.hashfunc = f 871 } 872 873 func (rt *Runtime) ExpectVerifySeal(seal proof.SealVerifyInfo, result error) { 874 rt.expectVerifySeal = &expectVerifySeal{ 875 seal: seal, 876 result: result, 877 } 878 } 879 880 func (rt *Runtime) ExpectComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo, cid cid.Cid, err error) { 881 rt.expectComputeUnsealedSectorCID = &expectComputeUnsealedSectorCID{ 882 reg, pieces, cid, err, 883 } 884 } 885 886 func (rt *Runtime) ExpectVerifyPoSt(post proof.WindowPoStVerifyInfo, result error) { 887 rt.expectVerifyPoSt = &expectVerifyPoSt{ 888 post: post, 889 result: result, 890 } 891 } 892 893 func (rt *Runtime) ExpectVerifyConsensusFault(h1, h2, extra []byte, result *runtime.ConsensusFault, resultErr error) { 894 rt.expectVerifyConsensusFault = &expectVerifyConsensusFault{ 895 requireCorrectInput: true, 896 BlockHeader1: h1, 897 BlockHeader2: h2, 898 BlockHeaderExtra: extra, 899 Fault: result, 900 Err: resultErr, 901 } 902 } 903 904 // Verifies that expected calls were received, and resets all expectations. 905 func (rt *Runtime) Verify() { 906 rt.t.Helper() 907 if rt.expectValidateCallerAny { 908 rt.failTest("expected ValidateCallerAny, not received") 909 } 910 if len(rt.expectValidateCallerAddr) > 0 { 911 rt.failTest("missing expected ValidateCallerAddr %v", rt.expectValidateCallerAddr) 912 } 913 if len(rt.expectValidateCallerType) > 0 { 914 rt.failTest("missing expected ValidateCallerType %v", rt.expectValidateCallerType) 915 } 916 if len(rt.expectRandomnessBeacon) > 0 { 917 rt.failTest("missing expected beacon randomness %v", rt.expectRandomnessBeacon) 918 } 919 if len(rt.expectRandomnessTickets) > 0 { 920 rt.failTest("missing expected ticket randomness %v", rt.expectRandomnessTickets) 921 } 922 if len(rt.expectSends) > 0 { 923 rt.failTest("missing expected send %v", rt.expectSends) 924 } 925 if len(rt.expectVerifySigs) > 0 { 926 rt.failTest("missing expected verify signature %v", rt.expectVerifySigs) 927 } 928 if rt.expectCreateActor != nil { 929 rt.failTest("missing expected create actor with code %s, address %s", 930 rt.expectCreateActor.codeId, rt.expectCreateActor.address) 931 } 932 933 if rt.expectVerifySeal != nil { 934 rt.failTest("missing expected verify seal with %v", rt.expectVerifySeal.seal) 935 } 936 937 if rt.expectBatchVerifySeals != nil { 938 rt.failTest("missing expected batch verify seals with %v", rt.expectBatchVerifySeals) 939 } 940 941 if rt.expectComputeUnsealedSectorCID != nil { 942 rt.failTest("missing expected ComputeUnsealedSectorCID with %v", rt.expectComputeUnsealedSectorCID) 943 } 944 945 if rt.expectVerifyPoSt != nil { 946 rt.failTest("missing expected PoSt verification with %v", rt.expectVerifyPoSt) 947 } 948 949 if rt.expectVerifyConsensusFault != nil { 950 rt.failTest("missing expected verify consensus fault") 951 } 952 if rt.expectDeleteActor != nil { 953 rt.failTest("missing expected delete actor with address %s", rt.expectDeleteActor.String()) 954 } 955 956 rt.Reset() 957 } 958 959 // Resets expectations 960 func (rt *Runtime) Reset() { 961 rt.expectValidateCallerAny = false 962 rt.expectValidateCallerAddr = nil 963 rt.expectValidateCallerType = nil 964 rt.expectRandomnessBeacon = nil 965 rt.expectRandomnessTickets = nil 966 rt.expectSends = nil 967 rt.expectCreateActor = nil 968 rt.expectVerifySigs = nil 969 rt.expectVerifySeal = nil 970 rt.expectBatchVerifySeals = nil 971 rt.expectComputeUnsealedSectorCID = nil 972 } 973 974 // Calls f() expecting it to invoke Runtime.Abortf() with a specified exit code. 975 func (rt *Runtime) ExpectAbort(expected exitcode.ExitCode, f func()) { 976 rt.ExpectAbortContainsMessage(expected, "", f) 977 } 978 979 // Calls f() expecting it to invoke Runtime.Abortf() with a specified exit code and message. 980 func (rt *Runtime) ExpectAbortContainsMessage(expected exitcode.ExitCode, substr string, f func()) { 981 rt.t.Helper() 982 prevState := rt.state 983 984 defer func() { 985 rt.t.Helper() 986 r := recover() 987 if r == nil { 988 rt.failTest("expected abort with code %v but call succeeded", expected) 989 return 990 } 991 a, ok := r.(abort) 992 if !ok { 993 panic(r) 994 } 995 if a.code != expected { 996 rt.failTest("abort expected code %v, got %v %s", expected, a.code, a.msg) 997 } 998 if substr != "" { 999 if !strings.Contains(a.msg, substr) { 1000 rt.failTest("abort expected message\n'%s'\nto contain\n'%s'\n", a.msg, substr) 1001 } 1002 } 1003 // Roll back state change. 1004 rt.state = prevState 1005 }() 1006 f() 1007 } 1008 1009 func (rt *Runtime) ExpectLogsContain(substr string) { 1010 for _, msg := range rt.logs { 1011 if strings.Contains(msg, substr) { 1012 return 1013 } 1014 } 1015 rt.failTest("logs contain %d message(s) and do not contain \"%s\"", len(rt.logs), substr) 1016 } 1017 1018 func (rt *Runtime) ClearLogs() { 1019 rt.logs = []string{} 1020 } 1021 1022 func (rt *Runtime) ExpectGasCharged(gas int64) { 1023 if gas != rt.gasCharged { 1024 rt.failTest("expected gas charged: %d, actual gas charged: %d", gas, rt.gasCharged) 1025 } 1026 } 1027 1028 func (rt *Runtime) Call(method interface{}, params interface{}) interface{} { 1029 meth := reflect.ValueOf(method) 1030 rt.verifyExportedMethodType(meth) 1031 1032 // There's no panic recovery here. If an abort is expected, this call will be inside an ExpectAbort block. 1033 // If not expected, the panic will escape and cause the test to fail. 1034 1035 rt.inCall = true 1036 rt.stateUsedObjs = map[cbor.Marshaler]cid.Cid{} 1037 defer func() { 1038 rt.inCall = false 1039 rt.stateUsedObjs = nil 1040 }() 1041 var arg reflect.Value 1042 if params != nil { 1043 arg = reflect.ValueOf(params) 1044 } else { 1045 arg = reflect.ValueOf(abi.Empty) 1046 } 1047 ret := meth.Call([]reflect.Value{reflect.ValueOf(rt), arg}) 1048 rt.checkStateObjectsUnmodified() 1049 return ret[0].Interface() 1050 } 1051 1052 // Checks that state objects weren't modified outside of transaction. 1053 func (rt *Runtime) checkStateObjectsUnmodified() { 1054 for obj, expectedKey := range rt.stateUsedObjs { // nolint:nomaprange 1055 // Recompute the CID of the object and check it's the same as was recorded 1056 // when the object was loaded. 1057 finalKey, _, err := ipld.MarshalCBOR(obj) 1058 if err != nil { 1059 rt.Abortf(exitcode.SysErrorIllegalActor, "error marshalling state object for validation: %v", err) 1060 } 1061 if finalKey != expectedKey { 1062 rt.Abortf(exitcode.SysErrorIllegalActor, "State mutated outside of transaction scope") 1063 } 1064 } 1065 } 1066 1067 func (rt *Runtime) verifyExportedMethodType(meth reflect.Value) { 1068 rt.t.Helper() 1069 t := meth.Type() 1070 rt.require(t.Kind() == reflect.Func, "%v is not a function", meth) 1071 rt.require(t.NumIn() == 2, "exported method %v must have two parameters, got %v", meth, t.NumIn()) 1072 rt.require(t.In(0) == typeOfRuntimeInterface, "exported method first parameter must be runtime, got %v", t.In(0)) 1073 rt.require(t.In(1).Kind() == reflect.Ptr, "exported method second parameter must be pointer to params, got %v", t.In(1)) 1074 rt.require(t.In(1).Implements(typeOfCborUnmarshaler), "exported method second parameter must be CBOR-unmarshalable params, got %v", t.In(1)) 1075 rt.require(t.NumOut() == 1, "exported method must return a single value") 1076 rt.require(t.Out(0).Implements(typeOfCborMarshaler), "exported method must return CBOR-marshalable value") 1077 } 1078 1079 func (rt *Runtime) requireInCall() { 1080 rt.t.Helper() 1081 rt.require(rt.inCall, "invalid runtime invocation outside of method call") 1082 } 1083 1084 func (rt *Runtime) require(predicate bool, msg string, args ...interface{}) { 1085 rt.t.Helper() 1086 if !predicate { 1087 rt.failTestNow(msg, args...) 1088 } 1089 } 1090 1091 func (rt *Runtime) failTest(msg string, args ...interface{}) { 1092 rt.t.Helper() 1093 rt.t.Logf(msg, args...) 1094 rt.t.Logf("%s", debug.Stack()) 1095 rt.t.Fail() 1096 } 1097 1098 func (rt *Runtime) failTestNow(msg string, args ...interface{}) { 1099 rt.t.Helper() 1100 rt.t.Logf(msg, args...) 1101 rt.t.Logf("%s", debug.Stack()) 1102 rt.t.FailNow() 1103 } 1104 1105 func (rt *Runtime) ChargeGas(_ string, gas, _ int64) { 1106 rt.gasCharged += gas 1107 } 1108 1109 func getMethodName(code cid.Cid, num abi.MethodNum) string { 1110 for _, actor := range exported.BuiltinActors() { 1111 if actor.Code().Equals(code) { 1112 exports := actor.Exports() 1113 if len(exports) <= int(num) { 1114 return "<invalid>" 1115 } 1116 meth := exports[num] 1117 if meth == nil { 1118 return "<invalid>" 1119 } 1120 name := goruntime.FuncForPC(reflect.ValueOf(meth).Pointer()).Name() 1121 name = strings.TrimSuffix(name, "-fm") 1122 lastDot := strings.LastIndexByte(name, '.') 1123 name = name[lastDot+1:] 1124 return name 1125 } 1126 } 1127 return "<unknown actor>" 1128 }