github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/contract_reader.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence/runtime" 7 "github.com/onflow/cadence/runtime/ast" 8 "github.com/onflow/cadence/runtime/common" 9 10 "github.com/koko1123/flow-go-1/fvm/errors" 11 "github.com/koko1123/flow-go-1/fvm/tracing" 12 "github.com/koko1123/flow-go-1/model/flow" 13 "github.com/koko1123/flow-go-1/module/trace" 14 ) 15 16 // ContractReader provide read access to contracts. 17 type ContractReader struct { 18 tracer tracing.TracerSpan 19 meter Meter 20 21 accounts Accounts 22 } 23 24 func NewContractReader( 25 tracer tracing.TracerSpan, 26 meter Meter, 27 accounts Accounts, 28 ) *ContractReader { 29 return &ContractReader{ 30 tracer: tracer, 31 meter: meter, 32 accounts: accounts, 33 } 34 } 35 36 func (reader *ContractReader) GetAccountContractNames( 37 address runtime.Address, 38 ) ( 39 []string, 40 error, 41 ) { 42 defer reader.tracer.StartChildSpan( 43 trace.FVMEnvGetAccountContractNames).End() 44 45 err := reader.meter.MeterComputation( 46 ComputationKindGetAccountContractNames, 47 1) 48 if err != nil { 49 return nil, fmt.Errorf("get account contract names failed: %w", err) 50 } 51 52 a := flow.Address(address) 53 54 freezeError := reader.accounts.CheckAccountNotFrozen(a) 55 if freezeError != nil { 56 return nil, fmt.Errorf( 57 "get account contract names failed: %w", 58 freezeError) 59 } 60 61 return reader.accounts.GetContractNames(a) 62 } 63 64 func (reader *ContractReader) ResolveLocation( 65 identifiers []runtime.Identifier, 66 location runtime.Location, 67 ) ( 68 []runtime.ResolvedLocation, 69 error, 70 ) { 71 defer reader.tracer.StartExtensiveTracingChildSpan( 72 trace.FVMEnvResolveLocation).End() 73 74 err := reader.meter.MeterComputation(ComputationKindResolveLocation, 1) 75 if err != nil { 76 return nil, fmt.Errorf("resolve location failed: %w", err) 77 } 78 79 addressLocation, isAddress := location.(common.AddressLocation) 80 81 // if the location is not an address location, e.g. an identifier location 82 // (`import Crypto`), then return a single resolved location which declares 83 // all identifiers. 84 if !isAddress { 85 return []runtime.ResolvedLocation{ 86 { 87 Location: location, 88 Identifiers: identifiers, 89 }, 90 }, nil 91 } 92 93 // if the location is an address, 94 // and no specific identifiers where requested in the import statement, 95 // then fetch all identifiers at this address 96 if len(identifiers) == 0 { 97 address := flow.Address(addressLocation.Address) 98 99 err := reader.accounts.CheckAccountNotFrozen(address) 100 if err != nil { 101 return nil, fmt.Errorf( 102 "resolving location's account frozen check failed: %w", 103 err) 104 } 105 106 contractNames, err := reader.accounts.GetContractNames(address) 107 if err != nil { 108 return nil, fmt.Errorf("resolving location failed: %w", err) 109 } 110 111 // if there are no contractNames deployed, 112 // then return no resolved locations 113 if len(contractNames) == 0 { 114 return nil, nil 115 } 116 117 identifiers = make([]ast.Identifier, len(contractNames)) 118 119 for i := range identifiers { 120 identifiers[i] = runtime.Identifier{ 121 Identifier: contractNames[i], 122 } 123 } 124 } 125 126 // return one resolved location per identifier. 127 // each resolved location is an address contract location 128 resolvedLocations := make([]runtime.ResolvedLocation, len(identifiers)) 129 for i := range resolvedLocations { 130 identifier := identifiers[i] 131 resolvedLocations[i] = runtime.ResolvedLocation{ 132 Location: common.AddressLocation{ 133 Address: addressLocation.Address, 134 Name: identifier.Identifier, 135 }, 136 Identifiers: []runtime.Identifier{identifier}, 137 } 138 } 139 140 return resolvedLocations, nil 141 } 142 143 func (reader *ContractReader) GetCode( 144 location runtime.Location, 145 ) ( 146 []byte, 147 error, 148 ) { 149 defer reader.tracer.StartChildSpan(trace.FVMEnvGetCode).End() 150 151 err := reader.meter.MeterComputation(ComputationKindGetCode, 1) 152 if err != nil { 153 return nil, fmt.Errorf("get code failed: %w", err) 154 } 155 156 contractLocation, ok := location.(common.AddressLocation) 157 if !ok { 158 return nil, errors.NewInvalidLocationErrorf( 159 location, 160 "expecting an AddressLocation, but other location types are passed") 161 } 162 163 address := flow.Address(contractLocation.Address) 164 165 err = reader.accounts.CheckAccountNotFrozen(address) 166 if err != nil { 167 return nil, fmt.Errorf("get code failed: %w", err) 168 } 169 170 add, err := reader.accounts.GetContract(contractLocation.Name, address) 171 if err != nil { 172 return nil, fmt.Errorf("get code failed: %w", err) 173 } 174 175 return add, nil 176 } 177 178 func (reader *ContractReader) GetAccountContractCode( 179 address runtime.Address, 180 name string, 181 ) ( 182 code []byte, 183 err error, 184 ) { 185 defer reader.tracer.StartChildSpan( 186 trace.FVMEnvGetAccountContractCode).End() 187 188 err = reader.meter.MeterComputation( 189 ComputationKindGetAccountContractCode, 190 1) 191 if err != nil { 192 return nil, fmt.Errorf("get account contract code failed: %w", err) 193 } 194 195 code, err = reader.GetCode(common.AddressLocation{ 196 Address: address, 197 Name: name, 198 }) 199 if err != nil { 200 return nil, fmt.Errorf("get account contract code failed: %w", err) 201 } 202 203 return code, nil 204 }