tests working now

This commit is contained in:
Jared Wasinger 2024-12-10 15:57:36 +07:00 committed by Felix Lange
parent 5cc853d807
commit c293caade9
2 changed files with 59 additions and 35 deletions

View File

@ -7,6 +7,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"golang.org/x/exp/rand" "golang.org/x/exp/rand"
"runtime/debug"
"testing" "testing"
) )
@ -144,6 +145,7 @@ func testLinkCase(t *testing.T, tcInput linkTestCaseInput) {
} }
if len(res.Addrs) != len(tcInput.expectDeployed) { if len(res.Addrs) != len(tcInput.expectDeployed) {
debug.PrintStack()
t.Fatalf("got %d deployed contracts. expected %d.\n", len(res.Addrs), len(tcInput.expectDeployed)) t.Fatalf("got %d deployed contracts. expected %d.\n", len(res.Addrs), len(tcInput.expectDeployed))
} }
for contract, _ := range tcInput.expectDeployed { for contract, _ := range tcInput.expectDeployed {
@ -164,6 +166,7 @@ func TestContractLinking(t *testing.T) {
}, },
}) })
fmt.Println("2")
testLinkCase(t, linkTestCaseInput{ testLinkCase(t, linkTestCaseInput{
map[rune][]rune{ map[rune][]rune{
'a': {'b', 'c', 'd', 'e'}, 'a': {'b', 'c', 'd', 'e'},

View File

@ -70,58 +70,66 @@ type depTreeBuilder struct {
// map of pattern to unlinked contract bytecode (for libraries or contracts) // map of pattern to unlinked contract bytecode (for libraries or contracts)
contracts map[string]string contracts map[string]string
// map of pattern to subtree represented by contract // map of pattern to subtree represented by contract
subtrees map[string]*depTreeNode subtrees map[string]any
// map of nodes that aren't referenced by other dependencies (these can be libraries too if user is doing lib-only deployment) // map of nodes that aren't referenced by other dependencies (these can be libraries too if user is doing lib-only deployment)
roots map[string]struct{} roots map[string]struct{}
} }
type depTreeNode struct { type depTreeNode struct {
pattern string pattern string
unlinkedCode string unlinkedCode string
nodes []*depTreeNode nodes []any
}
type overrideNode struct {
pattern string
addr common.Address
} }
func (d *depTreeBuilder) buildDepTrees(pattern, contract string) { func (d *depTreeBuilder) buildDepTrees(pattern, contract string) {
reMatchSpecificPattern, err := regexp.Compile("__\\$([a-f0-9]+)\\$__") // if the node is in the subtree set already, bail out early
if err != nil { if _, ok := d.subtrees[pattern]; ok {
panic(err) return
} }
if addr, ok := d.overrides[pattern]; ok {
node := &overrideNode{
pattern: pattern,
addr: addr,
}
d.subtrees[pattern] = node
} else {
node := &depTreeNode{ node := &depTreeNode{
pattern: pattern, pattern: pattern,
unlinkedCode: contract, unlinkedCode: contract,
} }
// if the node is an override node: add it to the node map but don't recurse on it.
// else if the node is depNode: recurse on it, and add it to the dep map.
reMatchSpecificPattern, err := regexp.Compile("__\\$([a-f0-9]+)\\$__")
if err != nil {
panic(err)
}
for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(contract, -1) { for _, match := range reMatchSpecificPattern.FindAllStringSubmatch(contract, -1) {
depPattern := match[1] depPattern := match[1]
if _, ok := d.subtrees[depPattern]; ok {
continue
}
if _, ok := d.overrides[depPattern]; ok {
continue
}
// this library was referenced by another contract. it's not a dependency tree root.
delete(d.roots, depPattern)
d.buildDepTrees(depPattern, d.contracts[depPattern]) d.buildDepTrees(depPattern, d.contracts[depPattern])
node.nodes = append(node.nodes, d.subtrees[depPattern]) node.nodes = append(node.nodes, d.subtrees[depPattern])
// this dep can't be a root dependency if it is referenced by other contracts.
delete(d.roots, depPattern)
} }
d.subtrees[pattern] = node d.subtrees[pattern] = node
}
} }
func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode) { func (d *depTreeBuilder) BuildDepTrees() (roots []*depTreeNode) {
for pattern, contract := range d.contracts { for pattern, contract := range d.contracts {
if _, ok := d.subtrees[pattern]; ok {
continue
}
if _, ok := d.overrides[pattern]; ok {
continue
}
// pattern has not been explored, it's potentially a root
d.roots[pattern] = struct{}{} d.roots[pattern] = struct{}{}
d.buildDepTrees(pattern, contract) d.buildDepTrees(pattern, contract)
} }
for pattern, _ := range d.roots { for pattern, _ := range d.roots {
roots = append(roots, d.subtrees[pattern]) switch node := d.subtrees[pattern].(type) {
case *depTreeNode:
roots = append(roots, node)
}
} }
return roots return roots
} }
@ -134,15 +142,28 @@ type treeDeployer struct {
err error err error
} }
func (d *treeDeployer) linkAndDeploy(node *depTreeNode) { func (d *treeDeployer) linkAndDeploy(n any) {
node, ok := n.(*depTreeNode)
if !ok {
// this was an override node
return
}
for _, childNode := range node.nodes { for _, childNode := range node.nodes {
d.linkAndDeploy(childNode) d.linkAndDeploy(childNode)
} }
// link in all node dependencies and produce the deployer bytecode // link in all node dependencies and produce the deployer bytecode
deployerCode := node.unlinkedCode deployerCode := node.unlinkedCode
for _, c := range node.nodes {
for _, child := range node.nodes { switch child := c.(type) {
case *depTreeNode:
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(d.deployedAddrs[child.pattern].String()[2:])) deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(d.deployedAddrs[child.pattern].String()[2:]))
case *overrideNode:
deployerCode = strings.ReplaceAll(deployerCode, "__$"+child.pattern+"$__", strings.ToLower(child.addr.String()[2:]))
default:
panic("invalid node type")
}
} }
// deploy the contract. // deploy the contract.
@ -175,13 +196,13 @@ func LinkAndDeploy(deployParams DeploymentParams, deploy func(input, deployer []
Addrs: make(map[string]common.Address), Addrs: make(map[string]common.Address),
} }
for _, meta := range deployParams.Contracts { for _, meta := range deployParams.Contracts {
unlinkedContracts[meta.Pattern] = meta.Bin unlinkedContracts[meta.Pattern] = meta.Bin[2:]
} }
// TODO: instantiate this using constructor // TODO: instantiate this using constructor
treeBuilder := depTreeBuilder{ treeBuilder := depTreeBuilder{
overrides: deployParams.Overrides, overrides: deployParams.Overrides,
contracts: unlinkedContracts, contracts: unlinkedContracts,
subtrees: make(map[string]*depTreeNode), subtrees: make(map[string]any),
roots: make(map[string]struct{}), roots: make(map[string]struct{}),
} }