Skip to content

Commit c005d43

Browse files
devbuggingpsiemens
andauthored
Blockchain refactor (#40)
* add emulator interface and base impl * add storage interface * add blockchain to scripts * upgrade flow-go * upgrade flow-go * added emulator implementation * add emulator dep * refactor emulator and computer * fix tests for emulator * migrate error parsing * remove old computer implementation * adding state * remove cache * remove un-needed data store properties * refactor in-memory storage * refactor script controller * refactor script model * add accounts controller * add tx controller * refactor project controller * add error model * add event model * refactor emulator * refactor transaction model to include factory * create state handler * refactor resolver with new controllers * server changes * unexport emulator * put back draft code for backward compatibility * account update * refactor blockchain api * tidy add dep * add some test and todo * fix project bug * add update account * script exe from flow * refactor script exe * add execute script and get account to state * put back account update * transaction from flow * refactor transaction exe * improve emulator API * improve the state API * improve the state API * adapt the change to the accounts * adapt the change to the projects * refactor resolver auth * improve script API * improve script API * improve script API * adapt API changes * test fix * fix nil bug * tx nil bug fix * fix migrate test * tidy * merge tidy * fix embed * delete already deleted files * rename state load * add mutex * refactor execute script api * bugfix mutex * refactor address model * address conversions * server logging * address translation * reset project * reset project * wip todo * Update blockchain/emulator.go Co-authored-by: Peter Siemens <peterjsiemens@gmail.com> * rename a function * rename state.go to projects.go * rename state to projects * encapsulate translate func * improve address shifting * improve address translation * add explicit sentry capture * add explicit sentry capture * add explicit sentry capture * add project id to account creation * without translation * added project tests * refactor mutex sync map and bugfix * cache reset test * no translation helper * fix playground test * update linter * lint * remove unused code * mod tidy * sync lint version * sync lint version * import lint * don't run tests twice * update headers * linting * add missing header * use the blockchain interface * add get latest block * reorganize * un-export variable * add empty address * add deploy test * bugfix translate addresses * refactor address translation * fixate number of init accounts * refactor init accounts number * fix script value translate * mod tidy * add headers * added script tests * move to adapters * add import test * move adapters to own module and use them in resolvers * tidy * refactor names * bugfix adapter * added contract name to resp test * add state on the get account * account state adapter * format * empty state Co-authored-by: Peter Siemens <peterjsiemens@gmail.com>
1 parent 8ab94d6 commit c005d43

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2778
-2504
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ jobs:
3434
uses: golangci/golangci-lint-action@v3.2.0
3535
with:
3636
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
37-
version: v1.46
37+
version: v1.47
3838
args: --timeout=10m

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ start-datastore-emulator:
4343
gcloud beta emulators datastore start --no-store-on-disk
4444

4545
.PHONY: ci
46-
ci: test check-tidy test check-headers
46+
ci: check-tidy test check-headers
4747

4848
.PHONY: install-linter
4949
install-linter:
50-
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ${GOPATH}/bin v1.46.1
50+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ${GOPATH}/bin v1.47.2
5151

5252
.PHONY: lint
5353
lint:

NOTICE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Flow Playground
2-
Copyright 2019-2021 Dapper Labs, Inc.
2+
Copyright 2019 Dapper Labs, Inc.
33

44
This product includes software developed at Dapper Labs, Inc. (https://www.dapperlabs.com/).

adapter/address.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Flow Playground
3+
*
4+
* Copyright 2019 Dapper Labs, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package adapter
20+
21+
import (
22+
"fmt"
23+
"regexp"
24+
"strconv"
25+
"strings"
26+
27+
"github.com/dapperlabs/flow-playground-api/model"
28+
)
29+
30+
// Backward compatibility address adapters.
31+
//
32+
// Because new blockchain execution is done using the emulator, it takes up first X accounts as service accounts, so if we
33+
// want to keep the same address space for the user we need to translate addresses coming from the user to the backend and vice-versa.
34+
// todo temp workaround to prevent API breaking changes, remove this in the v2.
35+
// We can avoid doing translations of address in the next version of playground we can start the address space at 0x0a.
36+
37+
const numberOfServiceAccounts = 4
38+
const addressLength = 8
39+
40+
// contentAddressFromAPI converts addresses found in content from the user input.
41+
func contentAddressFromAPI(input string) string {
42+
return contentAdapter(input, true)
43+
}
44+
45+
// contentAddressToAPI converts addresses found in content to the user output.
46+
func contentAddressToAPI(input string) string {
47+
return contentAdapter(input, false)
48+
}
49+
50+
func contentAdapter(input string, fromInput bool) string {
51+
r := regexp.MustCompile(`0x0*(\d+)`)
52+
53+
// we must use this logic since if we parse the address to Address type
54+
// it outputs it in standard format which might be different to the input format
55+
for _, addressMatch := range r.FindAllStringSubmatch(input, -1) {
56+
original := addressMatch[0]
57+
addr, _ := strconv.Atoi(addressMatch[1])
58+
59+
if fromInput {
60+
addr = addr + numberOfServiceAccounts
61+
} else if addr > numberOfServiceAccounts { // don't convert if service address, shouldn't happen
62+
addr = addr - numberOfServiceAccounts
63+
}
64+
65+
replaced := strings.ReplaceAll(original, addressMatch[1], fmt.Sprintf("%d", addr))
66+
input = strings.ReplaceAll(input, original, replaced)
67+
}
68+
69+
return input
70+
}
71+
72+
// addressFromAPI converts the address from the user input and shifts it for number of service accounts.
73+
func addressFromAPI(address model.Address) model.Address {
74+
var b model.Address // create a copy
75+
copy(b[:], address[:])
76+
b[len(b)-1] = b[len(b)-1] + numberOfServiceAccounts
77+
return b
78+
}
79+
80+
func addressesFromAPI(addresses []model.Address) []model.Address {
81+
for i, address := range addresses {
82+
addresses[i] = addressFromAPI(address)
83+
}
84+
return addresses
85+
}
86+
87+
// addressToAPI converts the address to the user output by subtracting the number of service accounts.
88+
func addressToAPI(address model.Address) model.Address {
89+
var b model.Address
90+
copy(b[addressLength-len(address):], address[:])
91+
b[len(b)-1] = b[len(b)-1] - numberOfServiceAccounts
92+
return b
93+
}
94+
95+
func addressesToAPI(addresses []model.Address) []model.Address {
96+
for i, address := range addresses {
97+
addresses[i] = addressToAPI(address)
98+
}
99+
return addresses
100+
}

adapter/address_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Flow Playground
3+
*
4+
* Copyright 2019 Dapper Labs, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package adapter
20+
21+
import (
22+
"fmt"
23+
"testing"
24+
25+
"github.com/dapperlabs/flow-playground-api/model"
26+
"gotest.tools/assert"
27+
)
28+
29+
func Test_ContentAdapter(t *testing.T) {
30+
testVectors := []struct {
31+
in string
32+
fromInput bool
33+
out string
34+
}{{
35+
in: "0x01",
36+
out: "0x05",
37+
fromInput: true,
38+
}, {
39+
in: "0x0000000000000001",
40+
out: "0x0000000000000005",
41+
fromInput: true,
42+
}, {
43+
in: "0x1",
44+
out: "0x5",
45+
fromInput: true,
46+
}, {
47+
in: `
48+
import Foo from 0x01
49+
import Zoo from 0x02
50+
import Goo from 0x03
51+
pub struct Bar {}
52+
`,
53+
out: `
54+
import Foo from 0x05
55+
import Zoo from 0x06
56+
import Goo from 0x07
57+
pub struct Bar {}
58+
`,
59+
fromInput: true,
60+
}, {
61+
in: "0x05",
62+
out: "0x01",
63+
fromInput: false,
64+
}, { // don't convert service addresses
65+
in: "0x01",
66+
out: "0x01",
67+
fromInput: false,
68+
}}
69+
70+
for _, vector := range testVectors {
71+
out := contentAdapter(vector.in, vector.fromInput)
72+
assert.Equal(t, vector.out, out, fmt.Sprintf("problem with input %v", vector))
73+
}
74+
}
75+
76+
func Test_AddressAdapter(t *testing.T) {
77+
t.Run("adapt from input", func(t *testing.T) {
78+
testVectors := [][]model.Address{
79+
{model.NewAddressFromString("0x01"), model.NewAddressFromString("0x05")},
80+
{model.NewAddressFromString("0x03"), model.NewAddressFromString("0x07")},
81+
}
82+
83+
for _, vector := range testVectors {
84+
out := addressFromAPI(vector[0])
85+
assert.Equal(t, vector[1], out)
86+
}
87+
})
88+
89+
t.Run("adapt to output", func(t *testing.T) {
90+
testVectors := [][]model.Address{
91+
{model.NewAddressFromString("0x05"), model.NewAddressFromString("0x01")},
92+
{model.NewAddressFromString("0x07"), model.NewAddressFromString("0x03")},
93+
}
94+
95+
for _, vector := range testVectors {
96+
out := addressToAPI(vector[0])
97+
assert.Equal(t, vector[1], out)
98+
}
99+
})
100+
}

adapter/models.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Flow Playground
3+
*
4+
* Copyright 2019 Dapper Labs, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package adapter
20+
21+
import "github.com/dapperlabs/flow-playground-api/model"
22+
23+
// models adapters compose different adapters in a single adapter.
24+
25+
func TransactionFromAPI(tx model.NewTransactionExecution) model.NewTransactionExecution {
26+
tx.Script = contentAddressFromAPI(tx.Script)
27+
tx.Signers = addressesFromAPI(tx.Signers)
28+
29+
for i, arg := range tx.Arguments {
30+
tx.Arguments[i] = contentAddressFromAPI(arg)
31+
}
32+
33+
return tx
34+
}
35+
36+
func TransactionToAPI(tx *model.TransactionExecution) *model.TransactionExecution {
37+
tx.Script = contentAddressToAPI(tx.Script)
38+
tx.Signers = addressesToAPI(tx.Signers)
39+
40+
for i, arg := range tx.Arguments {
41+
tx.Arguments[i] = contentAddressFromAPI(arg)
42+
}
43+
44+
for i, e := range tx.Events {
45+
for j, v := range e.Values {
46+
tx.Events[i].Values[j] = contentAddressToAPI(v)
47+
}
48+
}
49+
50+
for i, e := range tx.Errors {
51+
tx.Errors[i].Message = contentAddressToAPI(e.Message)
52+
}
53+
54+
return tx
55+
}
56+
57+
func TransactionsToAPI(txs []*model.TransactionExecution) []*model.TransactionExecution {
58+
for i, tx := range txs {
59+
txs[i] = TransactionToAPI(tx)
60+
}
61+
return txs
62+
}
63+
64+
func ScriptFromAPI(script model.NewScriptExecution) model.NewScriptExecution {
65+
script.Script = contentAddressFromAPI(script.Script)
66+
for i, a := range script.Arguments {
67+
script.Arguments[i] = contentAddressFromAPI(a)
68+
}
69+
return script
70+
}
71+
72+
func ScriptToAPI(script *model.ScriptExecution) *model.ScriptExecution {
73+
script.Script = contentAddressToAPI(script.Script)
74+
75+
for i, e := range script.Errors {
76+
script.Errors[i].Message = contentAddressToAPI(e.Message)
77+
}
78+
79+
for i, a := range script.Arguments {
80+
script.Arguments[i] = contentAddressToAPI(a)
81+
}
82+
83+
script.Value = contentAddressToAPI(script.Value)
84+
85+
return script
86+
}
87+
88+
func AccountToAPI(account *model.Account) *model.Account {
89+
account.Address = addressToAPI(account.Address)
90+
account.DeployedCode = contentAddressToAPI(account.DeployedCode)
91+
92+
account.State = stateToAPI(account.State)
93+
94+
return account
95+
}
96+
97+
func AccountsToAPI(accounts []*model.Account) []*model.Account {
98+
for i, a := range accounts {
99+
accounts[i] = AccountToAPI(a)
100+
}
101+
return accounts
102+
}
103+
104+
func AccountFromAPI(account model.UpdateAccount) model.UpdateAccount {
105+
if account.DeployedCode != nil {
106+
adaptedCode := contentAddressFromAPI(*account.DeployedCode)
107+
account.DeployedCode = &adaptedCode
108+
}
109+
return account
110+
}

adapter/state.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Flow Playground
3+
*
4+
* Copyright 2019 Dapper Labs, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package adapter
20+
21+
import "encoding/json"
22+
23+
type accountState struct {
24+
Private map[string]any
25+
Public map[string]any
26+
Storage map[string]any
27+
}
28+
29+
// stateToAPI removes any state values that are blockchain system values and not relevant to user usage of the playground.
30+
func stateToAPI(state string) string {
31+
if state == "" {
32+
return state
33+
}
34+
35+
var accState accountState
36+
_ = json.Unmarshal([]byte(state), &accState) // state will always be valid JSON
37+
38+
delete(accState.Public, "flowTokenBalance")
39+
delete(accState.Public, "flowTokenReceiver")
40+
delete(accState.Storage, "flowTokenVault")
41+
42+
// return empty as empty object, no keys - v0 adapter
43+
if len(accState.Public)+len(accState.Private)+len(accState.Storage) == 0 {
44+
emptyState, _ := json.Marshal("{}")
45+
return string(emptyState)
46+
}
47+
48+
adaptedState, _ := json.Marshal(accState)
49+
return string(adaptedState)
50+
}
51+
52+
// todo remove fee vaults

0 commit comments

Comments
 (0)