begin work on: Add checked_headers column for methods that are polled so taht we don’t duplicate; Add batching of method polling so that we arent generating a rediculously large account address list before using it to poll methods (or persist the list in pg?); User passed ABI and other ways to get ABI; Add ability to collect []byte and hashes from events and use them in method polling same manner as addresses; Event filter addrs => only those event’s addresses/hashes are used for polling; Option to persist seen address/hash/bytes lists into pg; Only generate lists of addresses, []byte, or hashes if a method will use them later
This commit is contained in:
parent
8c5b1b4dbe
commit
0a59f06cac
@ -67,9 +67,10 @@ func lightOmniWatcher() {
|
|||||||
for _, addr := range contractAddresses {
|
for _, addr := range contractAddresses {
|
||||||
t.SetEvents(addr, contractEvents)
|
t.SetEvents(addr, contractEvents)
|
||||||
t.SetMethods(addr, contractMethods)
|
t.SetMethods(addr, contractMethods)
|
||||||
t.SetEventAddrs(addr, eventAddrs)
|
t.SetEventArgs(addr, eventArgs)
|
||||||
t.SetMethodAddrs(addr, methodAddrs)
|
t.SetMethodArgs(addr, methodArgs)
|
||||||
t.SetRange(addr, [2]int64{startingBlockNumber, endingBlockNumber})
|
t.SetRange(addr, [2]int64{startingBlockNumber, endingBlockNumber})
|
||||||
|
t.SetCreateAddrList(addr, createAddrList)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := t.Init()
|
err := t.Init()
|
||||||
@ -90,11 +91,12 @@ func init() {
|
|||||||
|
|
||||||
lightOmniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for")
|
lightOmniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for")
|
||||||
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address")
|
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address")
|
||||||
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "contract-events", "e", []string{}, "Subset of events to watch; by default all events are watched")
|
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "events", "e", []string{}, "Subset of events to watch; by default all events are watched")
|
||||||
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "contract-methods", "m", nil, "Subset of methods to poll; by default no methods are polled")
|
lightOmniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "methods", "m", nil, "Subset of methods to poll; by default no methods are polled")
|
||||||
lightOmniWatcherCmd.Flags().StringArrayVarP(&eventAddrs, "event-filter-addresses", "f", []string{}, "Account addresses to persist event data for; default is to persist for all found token holder addresses")
|
lightOmniWatcherCmd.Flags().StringArrayVarP(&eventArgs, "event-args", "f", []string{}, "Argument values to filter event logs for; will only persist event logs that emit at least one of the value specified")
|
||||||
lightOmniWatcherCmd.Flags().StringArrayVarP(&methodAddrs, "method-filter-addresses", "g", []string{}, "Account addresses to poll methods with; default is to poll with all found token holder addresses")
|
lightOmniWatcherCmd.Flags().StringArrayVarP(&methodArgs, "method-args", "g", []string{}, "Argument values to limit methods to; will only call methods with emitted values that were specified here")
|
||||||
lightOmniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`)
|
lightOmniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`)
|
||||||
lightOmniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists")
|
lightOmniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists")
|
||||||
lightOmniWatcherCmd.Flags().Int64VarP(&endingBlockNumber, "ending-block-number", "d", -1, "Block to end watching- default is most recent block")
|
lightOmniWatcherCmd.Flags().Int64VarP(&endingBlockNumber, "ending-block-number", "d", -1, "Block to end watching- default is most recent block")
|
||||||
|
lightOmniWatcherCmd.Flags().BoolVarP(&createAddrList, "create-address-list", "c", false, "Set to true to persist address seen in emitted events into the database")
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,8 @@ func omniWatcher() {
|
|||||||
for _, addr := range contractAddresses {
|
for _, addr := range contractAddresses {
|
||||||
t.SetEvents(addr, contractEvents)
|
t.SetEvents(addr, contractEvents)
|
||||||
t.SetMethods(addr, contractMethods)
|
t.SetMethods(addr, contractMethods)
|
||||||
t.SetEventAddrs(addr, eventAddrs)
|
t.SetEventArgs(addr, eventArgs)
|
||||||
t.SetMethodAddrs(addr, methodAddrs)
|
t.SetMethodArgs(addr, methodArgs)
|
||||||
t.SetRange(addr, [2]int64{startingBlockNumber, endingBlockNumber})
|
t.SetRange(addr, [2]int64{startingBlockNumber, endingBlockNumber})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,11 +90,12 @@ func init() {
|
|||||||
|
|
||||||
omniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for")
|
omniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for")
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address")
|
omniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address")
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "contract-events", "e", []string{}, "Subset of events to watch; by default all events are watched")
|
omniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "events", "e", []string{}, "Subset of events to watch; by default all events are watched")
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "contract-methods", "m", nil, "Subset of methods to poll; by default no methods are polled")
|
omniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "methods", "m", nil, "Subset of methods to poll; by default no methods are polled")
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&eventAddrs, "event-filter-addresses", "f", []string{}, "Account addresses to persist event data for; default is to persist for all found token holder addresses")
|
omniWatcherCmd.Flags().StringArrayVarP(&eventArgs, "event-args", "f", []string{}, "Argument values to filter event logs for; will only persist event logs that emit at least one of the value specified")
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&methodAddrs, "method-filter-addresses", "g", []string{}, "Account addresses to poll methods with; default is to poll with all found token holder addresses")
|
omniWatcherCmd.Flags().StringArrayVarP(&methodArgs, "method-args", "g", []string{}, "Argument values to limit methods to; will only call methods with emitted values that were specified here")
|
||||||
omniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`)
|
omniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`)
|
||||||
omniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists")
|
omniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists")
|
||||||
omniWatcherCmd.Flags().Int64VarP(&endingBlockNumber, "ending-block-number", "d", -1, "Block to end watching- default is most recent block")
|
omniWatcherCmd.Flags().Int64VarP(&endingBlockNumber, "ending-block-number", "d", -1, "Block to end watching- default is most recent block")
|
||||||
|
omniWatcherCmd.Flags().BoolVarP(&createAddrList, "create-address-list", "c", false, "Set to true to persist address seen in emitted events into the database")
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,9 @@ var (
|
|||||||
contractAddresses []string
|
contractAddresses []string
|
||||||
contractEvents []string
|
contractEvents []string
|
||||||
contractMethods []string
|
contractMethods []string
|
||||||
eventAddrs []string
|
eventArgs []string
|
||||||
methodAddrs []string
|
methodArgs []string
|
||||||
|
createAddrList bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
@ -1,41 +1,46 @@
|
|||||||
|
Run lightSync, starting at the blockheight the ENS registry was published at.
|
||||||
|
`./vulcanize lightSync --config=./environments/<config.toml> --starting-block-number=3327417`
|
||||||
|
|
||||||
|
|
||||||
1. What is the label hash of this domain?
|
1. What is the label hash of this domain?
|
||||||
Q. Does this mean for a given namehash of "a.b.c" find keccak256(a), keccak256(b), and keccak256(c)? Do we know the parent domain and/or owner address?
|
Q. Does this mean for a given namehash of "a.b.c" where we don't know what "c" is find keccak256(c)? Do we know the parent domain and/or owner address?
|
||||||
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) events of the ENS Registry contract and filter for the root domain and/or owner address to narrow search
|
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) events of the ENS Registry contract and filter for the parent node and/or owner address to narrow search
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
||||||
2. For each node + label pair we find emitted, calculate the keccak256(abi.encodePacked(node, label)) and see if it matches our namehash
|
2. For each node + label pair we find emitted, calculate the keccak256(abi.encodePacked(node, label)) and see if it matches our domain's namehash
|
||||||
3. If it does, hash(label) is our answer
|
3. If it does, keccak256(label) is our label hash
|
||||||
|
|
||||||
2. What is the parent domain of this domain?
|
2. What is the parent domain of this domain?
|
||||||
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) events of the ENS Registry contract
|
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) events of the ENS Registry contract
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
||||||
2. Filter for our label (domain) and collect the node (parent domain namehash) that was emitted with it
|
2. If we know our label, filter for it and collect the node (parent domain namehash) that was emitted with it
|
||||||
3. Call the Registry's resolver(bytes32 node) method for the parent node to find the parent domain's Resolver
|
3. If we don't know our label I believe we need to take a similar aqpproach as in section 1 where we try every keccak256(abi.encodePacked(node, label)) until we find the namehash for our domain
|
||||||
4. Call its Resolver's name(bytes32 node) method for the parent node to find the parent domain's name
|
4. Call the Registry's resolver(bytes32 node) method for the parent node to find the parent domain's Resolver
|
||||||
|
5. Call its Resolver's name(bytes32 node) method for the parent node to find the parent domain's name
|
||||||
|
|
||||||
3. What are the subdomains of this domain?
|
3. What are the subdomains of this domain?
|
||||||
1. Watch NewOwner events of the ENS Registry contract
|
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) events of the ENS Registry contract
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner`
|
||||||
2. Filter for our node (domain) and collect all the labels emitted with it
|
2. Filter for our node (domain) and collect all the labels emitted with it
|
||||||
3. Calculate subdomain hashes: subnode = keccak256(abi.encodePacked(node, label));
|
3. Calculate subdomain hashes: subnode = keccak256(abi.encodePacked(node, label))
|
||||||
4. Call the Registry's resolver(bytes32 node) method for a subnode to find the subdomain's Resolver
|
4. Call the Registry's resolver(bytes32 node) method for a subnode to find the subdomain's Resolver
|
||||||
5. Call its Resolver's name(bytes32 node) method for a subnode to find the subdomain's name
|
5. Call its Resolver's name(bytes32 node) method for a subnode to find the subdomain's name
|
||||||
|
|
||||||
4. What domains does this address own?
|
4. What domains does this address own?
|
||||||
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) and Transfer(bytes32 indexed node, address owner) events of the ENS Registry contract and filter for the address
|
1. Watch NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) and Transfer(bytes32 indexed node, address owner) events of the ENS Registry contract and filter for the address
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-eevents=NewOwner --contract-events=Transfer --event-filter-addresses=<address>`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-eevents=NewOwner --contract-events=Transfer --event-filter-addresses=<address>`
|
||||||
2. Generate list of all nodes this address has ever owned
|
2. Collect node and label values; calculate subnodes = keccak256(abi.encodePacked(node, label))
|
||||||
3. Check which of these they still own at a given blockheight by iterating over the list and calling the owner(bytes32 node) method
|
3. Aggregate nodes and subnodes into a list and check which of these they still own at a given blockheight by iterating over the list and calling the Registry's owner(bytes32 node) method
|
||||||
4. Call the Registry's resolver(bytes32 node) method for a node to find the domain's Resolver
|
4. Call the Registry's resolver(bytes32 node) method for a node to find the domain's Resolver
|
||||||
5. Call its Resolver's name(bytes32 node) method for the node to find the domain's name
|
5. Call its Resolver's name(bytes32 node) method for the node to find the domain's name
|
||||||
|
|
||||||
5. What names point to this address?
|
5. What names point to this address?
|
||||||
Q. Is this in terms of which ENS nodes point to a given Resolver address? E.g. All nodes where the ENS records[node].resolver == address? Or is this in terms of Resolver records? E.g. All the records[node].names where the Resolver records[node].addr == address
|
Q. Is this in terms of which ENS nodes point to a given Resolver address? E.g. All nodes where the ENS records[node].resolver == address? Or is this in terms of Resolver records? E.g. All the records[node].names where the Resolver records[node].addr == address
|
||||||
1. In the former case, watch NewResolver(bytes32 indexed node, address resolver) events of the Registry and filter for the account address
|
1. In the former case, watch NewResolver(bytes32 indexed node, address resolver) events of the Registry and filter for the account address
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x1da022710dF5002339274AaDEe8D58218e9D6AB5 --contract-events=NewResolver --event-filter-addresses=<address>`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewResolver --event-filter-addresses=<address>`
|
||||||
2. Generate a list of nodes that have pointed to this resolver address
|
2. Generate a list of nodes that have pointed to this resolver address
|
||||||
3. Check which of these names still point at the address by iterating over the list and calling the resolver(bytes32 node) method
|
3. Check which of these still point at the address by iterating over the list and calling the Registry's resolver(bytes32 node) method
|
||||||
1. In the latter case, watch AddrChanged(bytes32 indexed node, address a) events of the Resolver and filter for the account address
|
1. In the latter case, watch AddrChanged(bytes32 indexed node, address a) events of the Resolver and filter for the account address
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x1da022710dF5002339274AaDEe8D58218e9D6AB5 --contract-events=AddrChanged --event-filter-addresses=<address>`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3648359 --contract-address=0x1da022710dF5002339274AaDEe8D58218e9D6AB5 --contract-events=AddrChanged --event-filter-addresses=<address>`
|
||||||
2. Generate our list of nodes that have pointed towards our address
|
2. Generate our list of nodes that have pointed towards our address
|
||||||
3. Check which of these they still own at a given blockheight by iterating over the list and calling the Resolver's addr(bytes32 node) method
|
3. Check which of these they still own at a given blockheight by iterating over the list and calling the Resolver's addr(bytes32 node) method
|
||||||
4. We can then fetch the string names of these nodes using the Resolver's name(bytes32 node) method.
|
4. We can then fetch the string names of these nodes using the Resolver's name(bytes32 node) method.
|
||||||
@ -48,9 +53,9 @@ we could also perform []byte filtering on the events and automate polling of eve
|
|||||||
currently working on adding this in, and once it is in you would be able to automate more of the steps in these processes.
|
currently working on adding this in, and once it is in you would be able to automate more of the steps in these processes.
|
||||||
|
|
||||||
E.g. you will be able to run
|
E.g. you will be able to run
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner --contract-events=Transfer --event-args=<address> --contract-methods=owner`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner --contract-events=Transfer --event-args=<address> --contract-methods=owner`
|
||||||
To automate the process in question 4 through step 3 (it will collect node []byte values emitted from the events it watches and then use those to call the owner method, persisting the results)
|
To automate the process in question 4 through step 3 (it will collect node []byte values emitted from the events it watches and then use those to call the owner method, persisting the results)
|
||||||
|
|
||||||
Or
|
Or
|
||||||
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=## --ending-block-numer=### --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner --event-args=<bytes-to-filter-for>`
|
`./vulcanize lightOmniWacther --config=./environments/<config.toml> --starting-block-number=3327417 --contract-address=0x314159265dD8dbb310642f98f50C066173C1259b --contract-events=NewOwner --event-args=<bytes-to-filter-for>`
|
||||||
To provide automated filtering for node []byte values in question 3.
|
To provide automated filtering for node []byte values in question 3.
|
@ -69,7 +69,9 @@ func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
strValues := make(map[string]string, len(values))
|
strValues := make(map[string]string, len(values))
|
||||||
|
seenBytes := make([]interface{}, 0, len(values))
|
||||||
|
seenAddrs := make([]interface{}, 0, len(values))
|
||||||
|
seenHashes := make([]interface{}, 0, len(values))
|
||||||
for fieldName, input := range values {
|
for fieldName, input := range values {
|
||||||
// Postgres cannot handle custom types, resolve to strings
|
// Postgres cannot handle custom types, resolve to strings
|
||||||
switch input.(type) {
|
switch input.(type) {
|
||||||
@ -79,10 +81,11 @@ func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (
|
|||||||
case common.Address:
|
case common.Address:
|
||||||
a := input.(common.Address)
|
a := input.(common.Address)
|
||||||
strValues[fieldName] = a.String()
|
strValues[fieldName] = a.String()
|
||||||
c.ContractInfo.AddTokenHolderAddress(a.String()) // cache address in a list of contract's token holder addresses
|
seenAddrs = append(seenAddrs, a)
|
||||||
case common.Hash:
|
case common.Hash:
|
||||||
h := input.(common.Hash)
|
h := input.(common.Hash)
|
||||||
strValues[fieldName] = h.String()
|
strValues[fieldName] = h.String()
|
||||||
|
seenHashes = append(seenHashes, h)
|
||||||
case string:
|
case string:
|
||||||
strValues[fieldName] = input.(string)
|
strValues[fieldName] = input.(string)
|
||||||
case bool:
|
case bool:
|
||||||
@ -90,6 +93,7 @@ func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (
|
|||||||
case []byte:
|
case []byte:
|
||||||
b := input.([]byte)
|
b := input.([]byte)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = string(b)
|
||||||
|
seenBytes = append(seenBytes, b)
|
||||||
case byte:
|
case byte:
|
||||||
b := input.(byte)
|
b := input.(byte)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = string(b)
|
||||||
@ -107,6 +111,17 @@ func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (
|
|||||||
Tx: watchedEvent.TxHash,
|
Tx: watchedEvent.TxHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache emitted values if their caching is turned on
|
||||||
|
if c.ContractInfo.EmittedAddrs != nil {
|
||||||
|
c.ContractInfo.AddEmittedAddr(seenAddrs...)
|
||||||
|
}
|
||||||
|
if c.ContractInfo.EmittedHashes != nil {
|
||||||
|
c.ContractInfo.AddEmittedHash(seenHashes...)
|
||||||
|
}
|
||||||
|
if c.ContractInfo.EmittedBytes != nil {
|
||||||
|
c.ContractInfo.AddEmittedBytes(seenBytes...)
|
||||||
|
}
|
||||||
|
|
||||||
return eventLog, nil
|
return eventLog, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,21 +81,21 @@ var _ = Describe("Converter", func() {
|
|||||||
_, err := c.Convert(mocks.MockTranferEvent, event)
|
_, err := c.Convert(mocks.MockTranferEvent, event)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
b, ok := con.TknHolderAddrs["0x000000000000000000000000000000000000Af21"]
|
b, ok := con.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
b, ok = con.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"]
|
b, ok = con.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs["0x"]
|
_, ok = con.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs[""]
|
_, ok = con.EmittedAddrs[""]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs["0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP"]
|
_, ok = con.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@ -63,8 +63,11 @@ type transformer struct {
|
|||||||
|
|
||||||
// Lists of addresses to filter event or method data
|
// Lists of addresses to filter event or method data
|
||||||
// before persisting; if empty no filter is applied
|
// before persisting; if empty no filter is applied
|
||||||
EventAddrs map[string][]string
|
EventArgs map[string][]string
|
||||||
MethodAddrs map[string][]string
|
MethodArgs map[string][]string
|
||||||
|
|
||||||
|
// Whether or not to create a list of token holder addresses for the contract in postgres
|
||||||
|
CreateAddrList map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformer takes in config for blockchain, database, and network id
|
// Transformer takes in config for blockchain, database, and network id
|
||||||
@ -81,8 +84,8 @@ func NewTransformer(network string, BC core.BlockChain, DB *postgres.DB) *transf
|
|||||||
WatchedEvents: map[string][]string{},
|
WatchedEvents: map[string][]string{},
|
||||||
WantedMethods: map[string][]string{},
|
WantedMethods: map[string][]string{},
|
||||||
ContractRanges: map[string][2]int64{},
|
ContractRanges: map[string][2]int64{},
|
||||||
EventAddrs: map[string][]string{},
|
EventArgs: map[string][]string{},
|
||||||
MethodAddrs: map[string][]string{},
|
MethodArgs: map[string][]string{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,25 +119,22 @@ func (t *transformer) Init() error {
|
|||||||
lastBlock = t.ContractRanges[contractAddr][1]
|
lastBlock = t.ContractRanges[contractAddr][1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get contract name
|
// Get contract name if it has one
|
||||||
var name = new(string)
|
var name = new(string)
|
||||||
err = t.FetchContractData(t.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
t.FetchContractData(t.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("unable to fetch contract name: %v\r\n", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any accidental duplicate inputs in filter addresses
|
// Remove any potential accidental duplicate inputs in arg filter values
|
||||||
EventAddrs := map[string]bool{}
|
eventArgs := map[string]bool{}
|
||||||
for _, addr := range t.EventAddrs[contractAddr] {
|
for _, arg := range t.EventArgs[contractAddr] {
|
||||||
EventAddrs[addr] = true
|
eventArgs[arg] = true
|
||||||
}
|
}
|
||||||
MethodAddrs := map[string]bool{}
|
methodArgs := map[string]bool{}
|
||||||
for _, addr := range t.MethodAddrs[contractAddr] {
|
for _, arg := range t.MethodArgs[contractAddr] {
|
||||||
MethodAddrs[addr] = true
|
methodArgs[arg] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate info into contract object
|
// Aggregate info into contract object
|
||||||
info := &contract.Contract{
|
info := contract.Contract{
|
||||||
Name: *name,
|
Name: *name,
|
||||||
Network: t.Network,
|
Network: t.Network,
|
||||||
Address: contractAddr,
|
Address: contractAddr,
|
||||||
@ -143,11 +143,11 @@ func (t *transformer) Init() error {
|
|||||||
StartingBlock: firstBlock,
|
StartingBlock: firstBlock,
|
||||||
LastBlock: lastBlock,
|
LastBlock: lastBlock,
|
||||||
Events: t.GetEvents(subset),
|
Events: t.GetEvents(subset),
|
||||||
Methods: t.GetAddrMethods(t.WantedMethods[contractAddr]),
|
Methods: t.GetSelectMethods(t.WantedMethods[contractAddr]),
|
||||||
EventAddrs: EventAddrs,
|
FilterArgs: eventArgs,
|
||||||
MethodAddrs: MethodAddrs,
|
MethodArgs: methodArgs,
|
||||||
TknHolderAddrs: map[string]bool{},
|
CreateAddrList: t.CreateAddrList[contractAddr],
|
||||||
}
|
}.Init()
|
||||||
|
|
||||||
// Use info to create filters
|
// Use info to create filters
|
||||||
err = info.GenerateFilters()
|
err = info.GenerateFilters()
|
||||||
@ -222,26 +222,31 @@ func (tr transformer) Execute() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their events to watch
|
// Used to set which contract addresses and which of their events to watch
|
||||||
func (t *transformer) SetEvents(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetEvents(contractAddr string, filterSet []string) {
|
||||||
t.WatchedEvents[contractAddr] = filterSet
|
tr.WatchedEvents[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set subset of account addresses to watch events for
|
// Used to set subset of account addresses to watch events for
|
||||||
func (t *transformer) SetEventAddrs(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetEventArgs(contractAddr string, filterSet []string) {
|
||||||
t.EventAddrs[contractAddr] = filterSet
|
tr.EventArgs[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their methods to call
|
// Used to set which contract addresses and which of their methods to call
|
||||||
func (t *transformer) SetMethods(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetMethods(contractAddr string, filterSet []string) {
|
||||||
t.WantedMethods[contractAddr] = filterSet
|
tr.WantedMethods[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set subset of account addresses to poll methods on
|
// Used to set subset of account addresses to poll methods on
|
||||||
func (t *transformer) SetMethodAddrs(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetMethodArgs(contractAddr string, filterSet []string) {
|
||||||
t.MethodAddrs[contractAddr] = filterSet
|
tr.MethodArgs[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set the block range to watch for a given address
|
// Used to set the block range to watch for a given address
|
||||||
func (t *transformer) SetRange(contractAddr string, rng [2]int64) {
|
func (tr *transformer) SetRange(contractAddr string, rng [2]int64) {
|
||||||
t.ContractRanges[contractAddr] = rng
|
tr.ContractRanges[contractAddr] = rng
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to set the block range to watch for a given address
|
||||||
|
func (tr *transformer) SetCreateAddrList(contractAddr string, on bool) {
|
||||||
|
tr.CreateAddrList[contractAddr] = on
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
@ -62,8 +63,8 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("Sets which account addresses to watch events for", func() {
|
It("Sets which account addresses to watch events for", func() {
|
||||||
eventAddrs := []string{"test1", "test2"}
|
eventAddrs := []string{"test1", "test2"}
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetEventAddrs(constants.TusdContractAddress, eventAddrs)
|
t.SetEventArgs(constants.TusdContractAddress, eventAddrs)
|
||||||
Expect(t.EventAddrs[constants.TusdContractAddress]).To(Equal(eventAddrs))
|
Expect(t.EventArgs[constants.TusdContractAddress]).To(Equal(eventAddrs))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -80,8 +81,8 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("Sets which account addresses to poll methods against", func() {
|
It("Sets which account addresses to poll methods against", func() {
|
||||||
methodAddrs := []string{"test1", "test2"}
|
methodAddrs := []string{"test1", "test2"}
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetMethodAddrs(constants.TusdContractAddress, methodAddrs)
|
t.SetMethodArgs(constants.TusdContractAddress, methodAddrs)
|
||||||
Expect(t.MethodAddrs[constants.TusdContractAddress]).To(Equal(methodAddrs))
|
Expect(t.MethodArgs[constants.TusdContractAddress]).To(Equal(methodAddrs))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -159,10 +160,10 @@ var _ = Describe("Transformer", func() {
|
|||||||
Expect(log.Value).To(Equal("1097077688018008265106216665536940668749033598146"))
|
Expect(log.Value).To(Equal("1097077688018008265106216665536940668749033598146"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related addresses while transforming event data", func() {
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -172,18 +173,24 @@ var _ = Describe("Transformer", func() {
|
|||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
b, ok := c.TknHolderAddrs["0x000000000000000000000000000000000000Af21"]
|
b, ok := c.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
b, ok = c.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"]
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
_, ok = c.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843b1234567890"]
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843b1234567890")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = c.TknHolderAddrs["0x"]
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[""]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -199,7 +206,12 @@ var _ = Describe("Transformer", func() {
|
|||||||
|
|
||||||
res := test_helpers.BalanceOf{}
|
res := test_helpers.BalanceOf{}
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0x000000000000000000000000000000000000Af21' AND block = '6194634'", constants.TusdContractAddress)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843bCE061BA391' AND block = '6194634'", constants.TusdContractAddress)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Balance).To(Equal("0"))
|
||||||
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843bCE061BA391' AND block = '6194634'", constants.TusdContractAddress)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Balance).To(Equal("0"))
|
Expect(res.Balance).To(Equal("0"))
|
||||||
Expect(res.TokenName).To(Equal("TrueUSD"))
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
||||||
@ -67,6 +68,9 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
}
|
}
|
||||||
|
|
||||||
strValues := make(map[string]string, len(values))
|
strValues := make(map[string]string, len(values))
|
||||||
|
seenBytes := make([]interface{}, 0, len(values))
|
||||||
|
seenAddrs := make([]interface{}, 0, len(values))
|
||||||
|
seenHashes := make([]interface{}, 0, len(values))
|
||||||
for fieldName, input := range values {
|
for fieldName, input := range values {
|
||||||
// Postgres cannot handle custom types, resolve everything to strings
|
// Postgres cannot handle custom types, resolve everything to strings
|
||||||
switch input.(type) {
|
switch input.(type) {
|
||||||
@ -76,17 +80,19 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
case common.Address:
|
case common.Address:
|
||||||
a := input.(common.Address)
|
a := input.(common.Address)
|
||||||
strValues[fieldName] = a.String()
|
strValues[fieldName] = a.String()
|
||||||
c.ContractInfo.AddTokenHolderAddress(a.String()) // cache address in a list of contract's token holder addresses
|
seenAddrs = append(seenAddrs, a)
|
||||||
case common.Hash:
|
case common.Hash:
|
||||||
h := input.(common.Hash)
|
h := input.(common.Hash)
|
||||||
strValues[fieldName] = h.String()
|
strValues[fieldName] = h.String()
|
||||||
|
seenHashes = append(seenHashes, h)
|
||||||
case string:
|
case string:
|
||||||
strValues[fieldName] = input.(string)
|
strValues[fieldName] = input.(string)
|
||||||
case bool:
|
case bool:
|
||||||
strValues[fieldName] = strconv.FormatBool(input.(bool))
|
strValues[fieldName] = strconv.FormatBool(input.(bool))
|
||||||
case []byte:
|
case []byte:
|
||||||
b := input.([]byte)
|
b := input.([]byte)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = hexutil.Encode(b)
|
||||||
|
seenBytes = append(seenBytes, b)
|
||||||
case byte:
|
case byte:
|
||||||
b := input.(byte)
|
b := input.(byte)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = string(b)
|
||||||
@ -109,6 +115,17 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
TransactionIndex: log.TxIndex,
|
TransactionIndex: log.TxIndex,
|
||||||
Id: headerID,
|
Id: headerID,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Cache emitted values if their caching is turned on
|
||||||
|
if c.ContractInfo.EmittedAddrs != nil {
|
||||||
|
c.ContractInfo.AddEmittedAddr(seenAddrs...)
|
||||||
|
}
|
||||||
|
if c.ContractInfo.EmittedHashes != nil {
|
||||||
|
c.ContractInfo.AddEmittedHash(seenHashes...)
|
||||||
|
}
|
||||||
|
if c.ContractInfo.EmittedBytes != nil {
|
||||||
|
c.ContractInfo.AddEmittedBytes(seenBytes...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,21 +84,21 @@ var _ = Describe("Converter", func() {
|
|||||||
_, err := c.Convert([]types.Log{mocks.MockTransferLog1, mocks.MockTransferLog2}, event, 232)
|
_, err := c.Convert([]types.Log{mocks.MockTransferLog1, mocks.MockTransferLog2}, event, 232)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
b, ok := con.TknHolderAddrs["0x000000000000000000000000000000000000Af21"]
|
b, ok := con.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
b, ok = con.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"]
|
b, ok = con.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs["0x"]
|
_, ok = con.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs[""]
|
_, ok = con.EmittedAddrs[""]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = con.TknHolderAddrs["0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP"]
|
_, ok = con.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
@ -85,7 +86,8 @@ func (r *headerRepository) MissingHeaders(startingBlockNumber int64, endingBlock
|
|||||||
LEFT JOIN checked_headers on headers.id = header_id
|
LEFT JOIN checked_headers on headers.id = header_id
|
||||||
WHERE (header_id ISNULL OR ` + eventID + ` IS FALSE)
|
WHERE (header_id ISNULL OR ` + eventID + ` IS FALSE)
|
||||||
AND headers.block_number >= $1
|
AND headers.block_number >= $1
|
||||||
AND headers.eth_node_fingerprint = $2`
|
AND headers.eth_node_fingerprint = $2
|
||||||
|
ORDER BY headers.block_number`
|
||||||
err = r.db.Select(&result, query, startingBlockNumber, r.db.Node.ID)
|
err = r.db.Select(&result, query, startingBlockNumber, r.db.Node.ID)
|
||||||
} else {
|
} else {
|
||||||
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
||||||
@ -93,7 +95,8 @@ func (r *headerRepository) MissingHeaders(startingBlockNumber int64, endingBlock
|
|||||||
WHERE (header_id ISNULL OR ` + eventID + ` IS FALSE)
|
WHERE (header_id ISNULL OR ` + eventID + ` IS FALSE)
|
||||||
AND headers.block_number >= $1
|
AND headers.block_number >= $1
|
||||||
AND headers.block_number <= $2
|
AND headers.block_number <= $2
|
||||||
AND headers.eth_node_fingerprint = $3`
|
AND headers.eth_node_fingerprint = $3
|
||||||
|
ORDER BY headers.block_number`
|
||||||
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func (r *blockRetriever) RetrieveFirstBlock() (int64, error) {
|
|||||||
var firstBlock int
|
var firstBlock int
|
||||||
err := r.db.Get(
|
err := r.db.Get(
|
||||||
&firstBlock,
|
&firstBlock,
|
||||||
"SELECT block_number FROM headers ORDER BY block_number ASC LIMIT 1",
|
"SELECT block_number FROM headers ORDER BY block_number LIMIT 1",
|
||||||
)
|
)
|
||||||
|
|
||||||
return int64(firstBlock), err
|
return int64(firstBlock), err
|
||||||
|
@ -18,7 +18,6 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -30,6 +29,7 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/light/repository"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/light/repository"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/light/retriever"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/light/retriever"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller"
|
||||||
srep "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository"
|
srep "github.com/vulcanize/vulcanizedb/pkg/omni/shared/repository"
|
||||||
@ -67,8 +67,11 @@ type transformer struct {
|
|||||||
|
|
||||||
// Lists of addresses to filter event or method data
|
// Lists of addresses to filter event or method data
|
||||||
// before persisting; if empty no filter is applied
|
// before persisting; if empty no filter is applied
|
||||||
EventAddrs map[string][]string
|
EventArgs map[string][]string
|
||||||
MethodAddrs map[string][]string
|
MethodArgs map[string][]string
|
||||||
|
|
||||||
|
// Whether or not to create a list of token holder addresses for the contract in postgres
|
||||||
|
CreateAddrList map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformer takes in config for blockchain, database, and network id
|
// Transformer takes in config for blockchain, database, and network id
|
||||||
@ -86,8 +89,9 @@ func NewTransformer(network string, bc core.BlockChain, db *postgres.DB) *transf
|
|||||||
WatchedEvents: map[string][]string{},
|
WatchedEvents: map[string][]string{},
|
||||||
WantedMethods: map[string][]string{},
|
WantedMethods: map[string][]string{},
|
||||||
ContractRanges: map[string][2]int64{},
|
ContractRanges: map[string][2]int64{},
|
||||||
EventAddrs: map[string][]string{},
|
EventArgs: map[string][]string{},
|
||||||
MethodAddrs: map[string][]string{},
|
MethodArgs: map[string][]string{},
|
||||||
|
CreateAddrList: map[string]bool{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,18 +130,18 @@ func (tr *transformer) Init() error {
|
|||||||
var name = new(string)
|
var name = new(string)
|
||||||
tr.FetchContractData(tr.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
tr.FetchContractData(tr.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
||||||
|
|
||||||
// Remove any potential accidental duplicate inputs in filter addresses
|
// Remove any potential accidental duplicate inputs in arg filter values
|
||||||
EventAddrs := map[string]bool{}
|
eventArgs := map[string]bool{}
|
||||||
for _, addr := range tr.EventAddrs[contractAddr] {
|
for _, arg := range tr.EventArgs[contractAddr] {
|
||||||
EventAddrs[addr] = true
|
eventArgs[arg] = true
|
||||||
}
|
}
|
||||||
MethodAddrs := map[string]bool{}
|
methodArgs := map[string]bool{}
|
||||||
for _, addr := range tr.MethodAddrs[contractAddr] {
|
for _, arg := range tr.MethodArgs[contractAddr] {
|
||||||
MethodAddrs[addr] = true
|
methodArgs[arg] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate info into contract object
|
// Aggregate info into contract object and store for execution
|
||||||
info := &contract.Contract{
|
tr.Contracts[contractAddr] = contract.Contract{
|
||||||
Name: *name,
|
Name: *name,
|
||||||
Network: tr.Network,
|
Network: tr.Network,
|
||||||
Address: contractAddr,
|
Address: contractAddr,
|
||||||
@ -146,14 +150,11 @@ func (tr *transformer) Init() error {
|
|||||||
StartingBlock: firstBlock,
|
StartingBlock: firstBlock,
|
||||||
LastBlock: lastBlock,
|
LastBlock: lastBlock,
|
||||||
Events: tr.GetEvents(subset),
|
Events: tr.GetEvents(subset),
|
||||||
Methods: tr.GetAddrMethods(tr.WantedMethods[contractAddr]),
|
Methods: tr.GetSelectMethods(tr.WantedMethods[contractAddr]),
|
||||||
EventAddrs: EventAddrs,
|
FilterArgs: eventArgs,
|
||||||
MethodAddrs: MethodAddrs,
|
MethodArgs: methodArgs,
|
||||||
TknHolderAddrs: map[string]bool{},
|
CreateAddrList: tr.CreateAddrList[contractAddr],
|
||||||
}
|
}.Init()
|
||||||
|
|
||||||
// Store contract info for execution
|
|
||||||
tr.Contracts[contractAddr] = info
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -216,14 +217,14 @@ func (tr *transformer) Execute() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll contract methods at this header's block height
|
||||||
|
// with arguments collected from event logs up to this point
|
||||||
|
if err := tr.PollContractAt(*con, header.BlockNumber); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// After persisting all watched event logs
|
|
||||||
// poller polls select contract methods
|
|
||||||
// and persists the results into custom pg tables
|
|
||||||
if err := tr.PollContract(*con); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -235,8 +236,8 @@ func (tr *transformer) SetEvents(contractAddr string, filterSet []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to set subset of account addresses to watch events for
|
// Used to set subset of account addresses to watch events for
|
||||||
func (tr *transformer) SetEventAddrs(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetEventArgs(contractAddr string, filterSet []string) {
|
||||||
tr.EventAddrs[contractAddr] = filterSet
|
tr.EventArgs[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their methods to call
|
// Used to set which contract addresses and which of their methods to call
|
||||||
@ -245,11 +246,16 @@ func (tr *transformer) SetMethods(contractAddr string, filterSet []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to set subset of account addresses to poll methods on
|
// Used to set subset of account addresses to poll methods on
|
||||||
func (tr *transformer) SetMethodAddrs(contractAddr string, filterSet []string) {
|
func (tr *transformer) SetMethodArgs(contractAddr string, filterSet []string) {
|
||||||
tr.MethodAddrs[contractAddr] = filterSet
|
tr.MethodArgs[contractAddr] = filterSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set the block range to watch for a given address
|
// Used to set the block range to watch for a given address
|
||||||
func (tr *transformer) SetRange(contractAddr string, rng [2]int64) {
|
func (tr *transformer) SetRange(contractAddr string, rng [2]int64) {
|
||||||
tr.ContractRanges[contractAddr] = rng
|
tr.ContractRanges[contractAddr] = rng
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to set the block range to watch for a given address
|
||||||
|
func (tr *transformer) SetCreateAddrList(contractAddr string, on bool) {
|
||||||
|
tr.CreateAddrList[contractAddr] = on
|
||||||
|
}
|
||||||
|
@ -18,6 +18,8 @@ package transformer_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
@ -59,8 +61,8 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("Sets which account addresses to watch events for", func() {
|
It("Sets which account addresses to watch events for", func() {
|
||||||
eventAddrs := []string{"test1", "test2"}
|
eventAddrs := []string{"test1", "test2"}
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetEventAddrs(constants.TusdContractAddress, eventAddrs)
|
t.SetEventArgs(constants.TusdContractAddress, eventAddrs)
|
||||||
Expect(t.EventAddrs[constants.TusdContractAddress]).To(Equal(eventAddrs))
|
Expect(t.EventArgs[constants.TusdContractAddress]).To(Equal(eventAddrs))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -77,8 +79,8 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("Sets which account addresses to poll methods against", func() {
|
It("Sets which account addresses to poll methods against", func() {
|
||||||
methodAddrs := []string{"test1", "test2"}
|
methodAddrs := []string{"test1", "test2"}
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetMethodAddrs(constants.TusdContractAddress, methodAddrs)
|
t.SetMethodArgs(constants.TusdContractAddress, methodAddrs)
|
||||||
Expect(t.MethodAddrs[constants.TusdContractAddress]).To(Equal(methodAddrs))
|
Expect(t.MethodArgs[constants.TusdContractAddress]).To(Equal(methodAddrs))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -164,10 +166,10 @@ var _ = Describe("Transformer", func() {
|
|||||||
Expect(log.Value).To(Equal("9998940000000000000000"))
|
Expect(log.Value).To(Equal("9998940000000000000000"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related addresses while transforming event data", func() {
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer("", blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -177,18 +179,24 @@ var _ = Describe("Transformer", func() {
|
|||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
b, ok := c.TknHolderAddrs["0x1062a747393198f70F71ec65A582423Dba7E5Ab3"]
|
b, ok := c.EmittedAddrs[common.HexToAddress("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
b, ok = c.TknHolderAddrs["0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0"]
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
_, ok = c.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843b1234567890"]
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843b1234567890")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
_, ok = c.TknHolderAddrs["0x"]
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[""]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -204,6 +212,17 @@ var _ = Describe("Transformer", func() {
|
|||||||
|
|
||||||
res := test_helpers.BalanceOf{}
|
res := test_helpers.BalanceOf{}
|
||||||
|
|
||||||
|
c, ok := t.Contracts[constants.TusdContractAddress]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok := c.EmittedAddrs[common.HexToAddress("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", constants.TusdContractAddress)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", constants.TusdContractAddress)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Balance).To(Equal("55849938025000000000000"))
|
Expect(res.Balance).To(Equal("55849938025000000000000"))
|
||||||
|
File diff suppressed because one or more lines are too long
@ -20,6 +20,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/filters"
|
"github.com/vulcanize/vulcanizedb/pkg/filters"
|
||||||
@ -38,13 +40,42 @@ type Contract struct {
|
|||||||
ParsedAbi abi.ABI // Parsed abi
|
ParsedAbi abi.ABI // Parsed abi
|
||||||
Events map[string]types.Event // Map of events to their names
|
Events map[string]types.Event // Map of events to their names
|
||||||
Methods map[string]types.Method // Map of methods to their names
|
Methods map[string]types.Method // Map of methods to their names
|
||||||
Filters map[string]filters.LogFilter // Map of event filters to their names
|
Filters map[string]filters.LogFilter // Map of event filters to their names; used only for full sync watcher
|
||||||
EventAddrs map[string]bool // User-input list of account addresses to watch events for
|
FilterArgs map[string]bool // User-input list of values to filter event logs for
|
||||||
MethodAddrs map[string]bool // User-input list of account addresses to poll methods for
|
MethodArgs map[string]bool // User-input list of values to limit method polling to
|
||||||
TknHolderAddrs map[string]bool // List of all contract-associated addresses, populated as events are transformed
|
EmittedAddrs map[interface{}]bool // List of all unique addresses collected from converted event logs
|
||||||
|
EmittedBytes map[interface{}]bool // List of all unique bytes collected from converted event logs
|
||||||
|
EmittedHashes map[interface{}]bool // List of all unique hashes collected from converted event logs
|
||||||
|
CreateAddrList bool // Whether or not to persist address list to postgres
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use contract info to generate event filters
|
// If we will be calling methods that use addr, hash, or byte arrays
|
||||||
|
// as arguments then we initialize map to hold these types of values
|
||||||
|
func (c Contract) Init() *Contract {
|
||||||
|
for _, method := range c.Methods {
|
||||||
|
for _, arg := range method.Args {
|
||||||
|
switch arg.Type.T {
|
||||||
|
case abi.AddressTy:
|
||||||
|
c.EmittedAddrs = map[interface{}]bool{}
|
||||||
|
case abi.HashTy:
|
||||||
|
c.EmittedHashes = map[interface{}]bool{}
|
||||||
|
case abi.BytesTy, abi.FixedBytesTy:
|
||||||
|
c.EmittedBytes = map[interface{}]bool{}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are creating an address list in postgres
|
||||||
|
// we initialize the map despite what method call, if any
|
||||||
|
if c.CreateAddrList {
|
||||||
|
c.EmittedAddrs = map[interface{}]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use contract info to generate event filters - full sync omni watcher only
|
||||||
func (c *Contract) GenerateFilters() error {
|
func (c *Contract) GenerateFilters() error {
|
||||||
c.Filters = map[string]filters.LogFilter{}
|
c.Filters = map[string]filters.LogFilter{}
|
||||||
|
|
||||||
@ -65,39 +96,45 @@ func (c *Contract) GenerateFilters() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if address is in list of addresses to
|
// Returns true if address is in list of arguments to
|
||||||
// filter events for or if no filtering is specified
|
// filter events for or if no filtering is specified
|
||||||
func (c *Contract) IsEventAddr(addr string) bool {
|
func (c *Contract) WantedEventArg(arg string) bool {
|
||||||
if c.EventAddrs == nil {
|
if c.FilterArgs == nil {
|
||||||
return false
|
return false
|
||||||
} else if len(c.EventAddrs) == 0 {
|
} else if len(c.FilterArgs) == 0 {
|
||||||
return true
|
return true
|
||||||
} else if a, ok := c.EventAddrs[addr]; ok {
|
} else if a, ok := c.FilterArgs[arg]; ok {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if address is in list of addresses to
|
// Returns true if address is in list of arguments to
|
||||||
// poll methods for or if no filtering is specified
|
// poll methods with or if no filtering is specified
|
||||||
func (c *Contract) IsMethodAddr(addr string) bool {
|
func (c *Contract) WantedMethodArg(arg interface{}) bool {
|
||||||
if c.MethodAddrs == nil {
|
if c.MethodArgs == nil {
|
||||||
return false
|
return false
|
||||||
} else if len(c.MethodAddrs) == 0 {
|
} else if len(c.MethodArgs) == 0 {
|
||||||
return true
|
return true
|
||||||
} else if a, ok := c.MethodAddrs[addr]; ok {
|
}
|
||||||
|
|
||||||
|
// resolve interface to one of the three types we handle as arguments
|
||||||
|
str := StringifyArg(arg)
|
||||||
|
|
||||||
|
// See if it's hex string has been filtered for
|
||||||
|
if a, ok := c.MethodArgs[str]; ok {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if mapping value matches filtered for address or if not filter exists
|
// Returns true if any mapping value matches filtered for address or if no filter exists
|
||||||
// Used to check if an event log name-value mapping should be filtered or not
|
// Used to check if an event log name-value mapping should be filtered or not
|
||||||
func (c *Contract) PassesEventFilter(args map[string]string) bool {
|
func (c *Contract) PassesEventFilter(args map[string]string) bool {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if c.IsEventAddr(arg) {
|
if c.WantedEventArg(arg) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,10 +142,47 @@ func (c *Contract) PassesEventFilter(args map[string]string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to add an address to the token holder address list
|
// Add event emitted address to our list if it passes filter and method polling is on
|
||||||
// if it is on the method polling list or the filter is open
|
func (c *Contract) AddEmittedAddr(addresses ...interface{}) {
|
||||||
func (c *Contract) AddTokenHolderAddress(addr string) {
|
for _, addr := range addresses {
|
||||||
if c.TknHolderAddrs != nil && c.IsMethodAddr(addr) {
|
if c.WantedMethodArg(addr) && c.Methods != nil {
|
||||||
c.TknHolderAddrs[addr] = true
|
c.EmittedAddrs[addr] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add event emitted hash to our list if it passes filter and method polling is on
|
||||||
|
func (c *Contract) AddEmittedHash(hashes ...interface{}) {
|
||||||
|
for _, hash := range hashes {
|
||||||
|
if c.WantedMethodArg(hash) && c.Methods != nil {
|
||||||
|
c.EmittedHashes[hash] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event emitted bytes to our list if it passes filter and method polling is on
|
||||||
|
func (c *Contract) AddEmittedBytes(byteArrays ...interface{}) {
|
||||||
|
for _, bytes := range byteArrays {
|
||||||
|
if c.WantedMethodArg(bytes) && c.Methods != nil {
|
||||||
|
c.EmittedBytes[bytes] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringifyArg(arg interface{}) (str string) {
|
||||||
|
switch arg.(type) {
|
||||||
|
case string:
|
||||||
|
str = arg.(string)
|
||||||
|
case common.Address:
|
||||||
|
a := arg.(common.Address)
|
||||||
|
str = a.String()
|
||||||
|
case common.Hash:
|
||||||
|
a := arg.(common.Hash)
|
||||||
|
str = a.String()
|
||||||
|
case []byte:
|
||||||
|
a := arg.([]byte)
|
||||||
|
str = hexutil.Encode(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Contract", func() {
|
var _ = Describe("Contract", func() {
|
||||||
@ -61,45 +62,45 @@ var _ = Describe("Contract", func() {
|
|||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
info = &contract.Contract{}
|
info = &contract.Contract{}
|
||||||
info.MethodAddrs = map[string]bool{}
|
info.MethodArgs = map[string]bool{}
|
||||||
info.EventAddrs = map[string]bool{}
|
info.FilterArgs = map[string]bool{}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns true if address is in event address filter list", func() {
|
It("Returns true if address is in event address filter list", func() {
|
||||||
info.EventAddrs["testAddress1"] = true
|
info.FilterArgs["testAddress1"] = true
|
||||||
info.EventAddrs["testAddress2"] = true
|
info.FilterArgs["testAddress2"] = true
|
||||||
|
|
||||||
is := info.IsEventAddr("testAddress1")
|
is := info.WantedEventArg("testAddress1")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
is = info.IsEventAddr("testAddress2")
|
is = info.WantedEventArg("testAddress2")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
|
|
||||||
info.MethodAddrs["testAddress3"] = true
|
info.MethodArgs["testAddress3"] = true
|
||||||
is = info.IsEventAddr("testAddress3")
|
is = info.WantedEventArg("testAddress3")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns true if event address filter is empty (no filter)", func() {
|
It("Returns true if event address filter is empty (no filter)", func() {
|
||||||
is := info.IsEventAddr("testAddress1")
|
is := info.WantedEventArg("testAddress1")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
is = info.IsEventAddr("testAddress2")
|
is = info.WantedEventArg("testAddress2")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns false if address is not in event address filter list", func() {
|
It("Returns false if address is not in event address filter list", func() {
|
||||||
info.EventAddrs["testAddress1"] = true
|
info.FilterArgs["testAddress1"] = true
|
||||||
info.EventAddrs["testAddress2"] = true
|
info.FilterArgs["testAddress2"] = true
|
||||||
|
|
||||||
is := info.IsEventAddr("testAddress3")
|
is := info.WantedEventArg("testAddress3")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns false if event address filter is nil (block all)", func() {
|
It("Returns false if event address filter is nil (block all)", func() {
|
||||||
info.EventAddrs = nil
|
info.FilterArgs = nil
|
||||||
|
|
||||||
is := info.IsEventAddr("testAddress1")
|
is := info.WantedEventArg("testAddress1")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
is = info.IsEventAddr("testAddress2")
|
is = info.WantedEventArg("testAddress2")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -107,45 +108,45 @@ var _ = Describe("Contract", func() {
|
|||||||
Describe("IsMethodAddr", func() {
|
Describe("IsMethodAddr", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
info = &contract.Contract{}
|
info = &contract.Contract{}
|
||||||
info.MethodAddrs = map[string]bool{}
|
info.MethodArgs = map[string]bool{}
|
||||||
info.EventAddrs = map[string]bool{}
|
info.FilterArgs = map[string]bool{}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns true if address is in method address filter list", func() {
|
It("Returns true if address is in method address filter list", func() {
|
||||||
info.MethodAddrs["testAddress1"] = true
|
info.MethodArgs["testAddress1"] = true
|
||||||
info.MethodAddrs["testAddress2"] = true
|
info.MethodArgs["testAddress2"] = true
|
||||||
|
|
||||||
is := info.IsMethodAddr("testAddress1")
|
is := info.WantedMethodArg("testAddress1")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
is = info.IsMethodAddr("testAddress2")
|
is = info.WantedMethodArg("testAddress2")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
|
|
||||||
info.EventAddrs["testAddress3"] = true
|
info.FilterArgs["testAddress3"] = true
|
||||||
is = info.IsMethodAddr("testAddress3")
|
is = info.WantedMethodArg("testAddress3")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns true if method address filter list is empty (no filter)", func() {
|
It("Returns true if method address filter list is empty (no filter)", func() {
|
||||||
is := info.IsMethodAddr("testAddress1")
|
is := info.WantedMethodArg("testAddress1")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
is = info.IsMethodAddr("testAddress2")
|
is = info.WantedMethodArg("testAddress2")
|
||||||
Expect(is).To(Equal(true))
|
Expect(is).To(Equal(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns false if address is not in method address filter list", func() {
|
It("Returns false if address is not in method address filter list", func() {
|
||||||
info.MethodAddrs["testAddress1"] = true
|
info.MethodArgs["testAddress1"] = true
|
||||||
info.MethodAddrs["testAddress2"] = true
|
info.MethodArgs["testAddress2"] = true
|
||||||
|
|
||||||
is := info.IsMethodAddr("testAddress3")
|
is := info.WantedMethodArg("testAddress3")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Returns false if method address filter list is nil (block all)", func() {
|
It("Returns false if method address filter list is nil (block all)", func() {
|
||||||
info.MethodAddrs = nil
|
info.MethodArgs = nil
|
||||||
|
|
||||||
is := info.IsMethodAddr("testAddress1")
|
is := info.WantedMethodArg("testAddress1")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
is = info.IsMethodAddr("testAddress2")
|
is = info.WantedMethodArg("testAddress2")
|
||||||
Expect(is).To(Equal(false))
|
Expect(is).To(Equal(false))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -154,14 +155,14 @@ var _ = Describe("Contract", func() {
|
|||||||
var mapping map[string]string
|
var mapping map[string]string
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
info = &contract.Contract{}
|
info = &contract.Contract{}
|
||||||
info.EventAddrs = map[string]bool{}
|
info.FilterArgs = map[string]bool{}
|
||||||
mapping = map[string]string{}
|
mapping = map[string]string{}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Return true if event log name-value mapping has filtered for address as a value", func() {
|
It("Return true if event log name-value mapping has filtered for address as a value", func() {
|
||||||
info.EventAddrs["testAddress1"] = true
|
info.FilterArgs["testAddress1"] = true
|
||||||
info.EventAddrs["testAddress2"] = true
|
info.FilterArgs["testAddress2"] = true
|
||||||
|
|
||||||
mapping["testInputName1"] = "testAddress1"
|
mapping["testInputName1"] = "testAddress1"
|
||||||
mapping["testInputName2"] = "testAddress2"
|
mapping["testInputName2"] = "testAddress2"
|
||||||
@ -181,8 +182,8 @@ var _ = Describe("Contract", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Return false if event log name-value mapping does not have filtered for address as a value", func() {
|
It("Return false if event log name-value mapping does not have filtered for address as a value", func() {
|
||||||
info.EventAddrs["testAddress1"] = true
|
info.FilterArgs["testAddress1"] = true
|
||||||
info.EventAddrs["testAddress2"] = true
|
info.FilterArgs["testAddress2"] = true
|
||||||
|
|
||||||
mapping["testInputName3"] = "testAddress3"
|
mapping["testInputName3"] = "testAddress3"
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ var _ = Describe("Contract", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Return false if event address filter list is nil (block all)", func() {
|
It("Return false if event address filter list is nil (block all)", func() {
|
||||||
info.EventAddrs = nil
|
info.FilterArgs = nil
|
||||||
|
|
||||||
mapping["testInputName1"] = "testAddress1"
|
mapping["testInputName1"] = "testAddress1"
|
||||||
mapping["testInputName2"] = "testAddress2"
|
mapping["testInputName2"] = "testAddress2"
|
||||||
@ -202,32 +203,33 @@ var _ = Describe("Contract", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("AddTokenHolderAddress", func() {
|
Describe("AddEmittedAddr", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
info = &contract.Contract{}
|
info = &contract.Contract{}
|
||||||
info.EventAddrs = map[string]bool{}
|
info.FilterArgs = map[string]bool{}
|
||||||
info.MethodAddrs = map[string]bool{}
|
info.MethodArgs = map[string]bool{}
|
||||||
info.TknHolderAddrs = map[string]bool{}
|
info.Methods = map[string]types.Method{}
|
||||||
|
info.EmittedAddrs = map[interface{}]bool{}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Adds address to list if it is on the method filter address list", func() {
|
It("Adds address to list if it is on the method filter address list", func() {
|
||||||
info.MethodAddrs["testAddress2"] = true
|
info.MethodArgs["testAddress2"] = true
|
||||||
info.AddTokenHolderAddress("testAddress2")
|
info.AddEmittedAddr("testAddress2")
|
||||||
b := info.TknHolderAddrs["testAddress2"]
|
b := info.EmittedAddrs["testAddress2"]
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Adds address to list if method filter is empty", func() {
|
It("Adds address to list if method filter is empty", func() {
|
||||||
info.AddTokenHolderAddress("testAddress2")
|
info.AddEmittedAddr("testAddress2")
|
||||||
b := info.TknHolderAddrs["testAddress2"]
|
b := info.EmittedAddrs["testAddress2"]
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Does not add address to list if both filters are closed (nil)", func() {
|
It("Does not add address to list if both filters are closed (nil)", func() {
|
||||||
info.EventAddrs = nil // close both
|
info.FilterArgs = nil // close both
|
||||||
info.MethodAddrs = nil
|
info.MethodArgs = nil
|
||||||
info.AddTokenHolderAddress("testAddress1")
|
info.AddEmittedAddr("testAddress1")
|
||||||
b := info.TknHolderAddrs["testAddress1"]
|
b := info.EmittedAddrs["testAddress1"]
|
||||||
Expect(b).To(Equal(false))
|
Expect(b).To(Equal(false))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -136,17 +136,19 @@ func SetupTusdContract(wantedEvents, wantedMethods []string) *contract.Contract
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
return &contract.Contract{
|
return &contract.Contract{
|
||||||
Name: "TrueUSD",
|
Name: "TrueUSD",
|
||||||
Address: constants.TusdContractAddress,
|
Address: constants.TusdContractAddress,
|
||||||
Abi: p.Abi(),
|
Abi: p.Abi(),
|
||||||
ParsedAbi: p.ParsedAbi(),
|
ParsedAbi: p.ParsedAbi(),
|
||||||
StartingBlock: 6194634,
|
StartingBlock: 6194634,
|
||||||
LastBlock: 6507323,
|
LastBlock: 6507323,
|
||||||
Events: p.GetEvents(wantedEvents),
|
Events: p.GetEvents(wantedEvents),
|
||||||
Methods: p.GetMethods(wantedMethods),
|
Methods: p.GetMethods(wantedMethods),
|
||||||
EventAddrs: map[string]bool{},
|
MethodArgs: map[string]bool{},
|
||||||
MethodAddrs: map[string]bool{},
|
FilterArgs: map[string]bool{},
|
||||||
TknHolderAddrs: map[string]bool{},
|
EmittedAddrs: map[interface{}]bool{},
|
||||||
|
EmittedBytes: map[interface{}]bool{},
|
||||||
|
EmittedHashes: map[interface{}]bool{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +180,10 @@ func TearDown(db *postgres.DB) {
|
|||||||
_, err = tx.Exec(`ALTER TABLE public.checked_headers DROP COLUMN IF EXISTS transfer_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e`)
|
_, err = tx.Exec(`ALTER TABLE public.checked_headers DROP COLUMN IF EXISTS transfer_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e`)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, err = tx.Exec(`DROP SCHEMA IF EXISTS full_0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E CASCADE`)
|
_, err = tx.Exec(`DROP SCHEMA IF EXISTS full_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e CASCADE`)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, err = tx.Exec(`DROP SCHEMA IF EXISTS light_0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E CASCADE`)
|
_, err = tx.Exec(`DROP SCHEMA IF EXISTS light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e CASCADE`)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
|
@ -17,9 +17,13 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +34,7 @@ type Parser interface {
|
|||||||
Abi() string
|
Abi() string
|
||||||
ParsedAbi() abi.ABI
|
ParsedAbi() abi.ABI
|
||||||
GetMethods(wanted []string) map[string]types.Method
|
GetMethods(wanted []string) map[string]types.Method
|
||||||
GetAddrMethods(wanted []string) map[string]types.Method
|
GetSelectMethods(wanted []string) map[string]types.Method
|
||||||
GetEvents(wanted []string) map[string]types.Event
|
GetEvents(wanted []string) map[string]types.Event
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,41 +63,47 @@ func (p *parser) ParsedAbi() abi.ABI {
|
|||||||
// Retrieves and parses the abi string
|
// Retrieves and parses the abi string
|
||||||
// for the given contract address
|
// for the given contract address
|
||||||
func (p *parser) Parse(contractAddr string) error {
|
func (p *parser) Parse(contractAddr string) error {
|
||||||
|
// If the abi is one our locally stored abis, fetch
|
||||||
|
// TODO: Allow users to pass abis through config
|
||||||
|
knownAbi, err := p.lookUp(contractAddr)
|
||||||
|
if err == nil {
|
||||||
|
p.abi = knownAbi
|
||||||
|
p.parsedAbi, err = geth.ParseAbi(knownAbi)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Try getting abi from etherscan
|
||||||
abiStr, err := p.client.GetAbi(contractAddr)
|
abiStr, err := p.client.GetAbi(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
//TODO: Implement other ways to fetch abi
|
||||||
p.abi = abiStr
|
p.abi = abiStr
|
||||||
p.parsedAbi, err = geth.ParseAbi(abiStr)
|
p.parsedAbi, err = geth.ParseAbi(abiStr)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *parser) lookUp(contractAddr string) (string, error) {
|
||||||
|
if v, ok := constants.Abis[common.HexToAddress(contractAddr)]; ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("ABI not present in lookup tabe")
|
||||||
|
}
|
||||||
|
|
||||||
// Returns wanted methods, if they meet the criteria, as map of types.Methods
|
// Returns wanted methods, if they meet the criteria, as map of types.Methods
|
||||||
// Empty wanted array => all methods that fit are returned
|
// Empty wanted array => all methods that fit are returned
|
||||||
// Nil wanted array => no events are returned
|
// Nil wanted array => no events are returned
|
||||||
func (p *parser) GetAddrMethods(wanted []string) map[string]types.Method {
|
func (p *parser) GetSelectMethods(wanted []string) map[string]types.Method {
|
||||||
addrMethods := map[string]types.Method{}
|
addrMethods := map[string]types.Method{}
|
||||||
if wanted == nil {
|
if wanted == nil {
|
||||||
return addrMethods
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range p.parsedAbi.Methods {
|
for _, m := range p.parsedAbi.Methods {
|
||||||
// Only return methods that have less than 3 inputs, 1 output, and wanted
|
if okInputTypes(m, wanted) {
|
||||||
if len(m.Inputs) < 3 && len(m.Outputs) == 1 && (len(wanted) == 0 || stringInSlice(wanted, m.Name)) {
|
wantedMethod := types.NewMethod(m)
|
||||||
addrsOnly := true
|
addrMethods[wantedMethod.Name] = wantedMethod
|
||||||
for _, input := range m.Inputs {
|
|
||||||
if input.Type.T != abi.AddressTy {
|
|
||||||
addrsOnly = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only return methods if inputs are all of type address and output is of the accepted types
|
|
||||||
if addrsOnly && wantType(m.Outputs[0]) {
|
|
||||||
method := types.NewMethod(m)
|
|
||||||
addrMethods[method.Name] = method
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +148,20 @@ func (p *parser) GetEvents(wanted []string) map[string]types.Event {
|
|||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
func wantType(arg abi.Argument) bool {
|
func okReturnType(arg abi.Argument) bool {
|
||||||
wanted := []byte{abi.UintTy, abi.IntTy, abi.BoolTy, abi.StringTy, abi.AddressTy, abi.HashTy}
|
wantedTypes := []byte{
|
||||||
for _, ty := range wanted {
|
abi.UintTy,
|
||||||
|
abi.IntTy,
|
||||||
|
abi.BoolTy,
|
||||||
|
abi.StringTy,
|
||||||
|
abi.AddressTy,
|
||||||
|
abi.HashTy,
|
||||||
|
abi.BytesTy,
|
||||||
|
abi.FixedBytesTy,
|
||||||
|
abi.FixedPointTy,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ty := range wantedTypes {
|
||||||
if arg.Type.T == ty {
|
if arg.Type.T == ty {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -149,6 +170,27 @@ func wantType(arg abi.Argument) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func okInputTypes(m abi.Method, wanted []string) bool {
|
||||||
|
// Only return method if it has less than 3 arguments, a single output value, and it is a method we want or we want all methods (empty 'wanted' slice)
|
||||||
|
if len(m.Inputs) < 3 && len(m.Outputs) == 1 && (len(wanted) == 0 || stringInSlice(wanted, m.Name)) {
|
||||||
|
// Only return methods if inputs are all of accepted types and output is of the accepted types
|
||||||
|
if !okReturnType(m.Outputs[0]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, input := range m.Inputs {
|
||||||
|
switch input.Type.T {
|
||||||
|
case abi.AddressTy, abi.HashTy, abi.BytesTy, abi.FixedBytesTy:
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func stringInSlice(list []string, s string) bool {
|
func stringInSlice(list []string, s string) bool {
|
||||||
for _, b := range list {
|
for _, b := range list {
|
||||||
if b == s {
|
if b == s {
|
||||||
|
@ -174,14 +174,14 @@ var _ = Describe("Parser", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Describe("GetAddrMethods", func() {
|
Describe("GetAddrMethods", func() {
|
||||||
It("Parses and returns only methods whose inputs, if any, are all addresses", func() {
|
It("Parses and returns only methods whose inputs, if any, are all of type address, hash or []byte", func() {
|
||||||
contractAddr := "0xDdE2D979e8d39BB8416eAfcFC1758f3CaB2C9C72"
|
contractAddr := "0xDdE2D979e8d39BB8416eAfcFC1758f3CaB2C9C72"
|
||||||
err = p.Parse(contractAddr)
|
err = p.Parse(contractAddr)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
wanted := []string{"isApprovedForAll", "supportsInterface", "getApproved", "totalSupply", "balanceOf"}
|
wanted := []string{"isApprovedForAll", "supportsInterface", "getApproved", "totalSupply", "balanceOf"}
|
||||||
|
|
||||||
methods := p.GetMethods(wanted)
|
methods := p.GetMethods(wanted)
|
||||||
selectMethods := p.GetAddrMethods(wanted)
|
selectMethods := p.GetSelectMethods(wanted)
|
||||||
|
|
||||||
_, ok := selectMethods["totalSupply"]
|
_, ok := selectMethods["totalSupply"]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
@ -199,7 +199,7 @@ var _ = Describe("Parser", func() {
|
|||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
_, ok = selectMethods["supportsInterface"]
|
_, ok = selectMethods["supportsInterface"]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(true))
|
||||||
_, ok = methods["supportsInterface"]
|
_, ok = methods["supportsInterface"]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@ -33,6 +35,7 @@ import (
|
|||||||
|
|
||||||
type Poller interface {
|
type Poller interface {
|
||||||
PollContract(con contract.Contract) error
|
PollContract(con contract.Contract) error
|
||||||
|
PollContractAt(con contract.Contract, blockNumber int64) error
|
||||||
FetchContractData(contractAbi, contractAddress, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error
|
FetchContractData(contractAbi, contractAddress, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,22 +53,28 @@ func NewPoller(blockChain core.BlockChain, db *postgres.DB, mode types.Mode) *po
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to call contract's methods found in abi using list of contract-related addresses
|
|
||||||
func (p *poller) PollContract(con contract.Contract) error {
|
func (p *poller) PollContract(con contract.Contract) error {
|
||||||
|
for i := con.StartingBlock; i <= con.LastBlock; i++ {
|
||||||
|
p.PollContractAt(con, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *poller) PollContractAt(con contract.Contract, blockNumber int64) error {
|
||||||
p.contract = con
|
p.contract = con
|
||||||
// Iterate over each of the contracts methods
|
|
||||||
for _, m := range con.Methods {
|
for _, m := range con.Methods {
|
||||||
switch len(m.Args) {
|
switch len(m.Args) {
|
||||||
case 0:
|
case 0:
|
||||||
if err := p.pollNoArg(m); err != nil {
|
if err := p.pollNoArgAt(m, blockNumber); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if err := p.pollSingleArg(m); err != nil {
|
if err := p.pollSingleArgAt(m, blockNumber); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
if err := p.pollDoubleArg(m); err != nil {
|
if err := p.pollDoubleArgAt(m, blockNumber); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -77,61 +86,137 @@ func (p *poller) PollContract(con contract.Contract) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll methods that take no arguments
|
func (p *poller) pollNoArgAt(m types.Method, bn int64) error {
|
||||||
func (p *poller) pollNoArg(m types.Method) error {
|
|
||||||
result := types.Result{
|
result := types.Result{
|
||||||
|
Block: bn,
|
||||||
Method: m,
|
Method: m,
|
||||||
Inputs: nil,
|
Inputs: nil,
|
||||||
PgType: m.Return[0].PgType,
|
PgType: m.Return[0].PgType,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := p.contract.StartingBlock; i <= p.contract.LastBlock; i++ {
|
var out interface{}
|
||||||
var out interface{}
|
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, nil, &out, bn)
|
||||||
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, nil, &out, i)
|
if err != nil {
|
||||||
if err != nil {
|
return errors.New(fmt.Sprintf("poller error calling 0 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
return errors.New(fmt.Sprintf("poller error calling 0 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
strOut, err := stringify(out)
|
strOut, err := stringify(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Output = strOut
|
result.Output = strOut
|
||||||
result.Block = i
|
|
||||||
|
|
||||||
// Persist result immediately
|
// Persist result immediately
|
||||||
err = p.PersistResult(result, p.contract.Address, p.contract.Name)
|
err = p.PersistResults([]types.Result{result}, m, p.contract.Address, p.contract.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("poller error persisting 0 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
return errors.New(fmt.Sprintf("poller error persisting 0 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use token holder address to poll methods that take 1 address argument (e.g. balanceOf)
|
// Use token holder address to poll methods that take 1 address argument (e.g. balanceOf)
|
||||||
func (p *poller) pollSingleArg(m types.Method) error {
|
func (p *poller) pollSingleArgAt(m types.Method, bn int64) error {
|
||||||
result := types.Result{
|
result := types.Result{
|
||||||
|
Block: bn,
|
||||||
Method: m,
|
Method: m,
|
||||||
Inputs: make([]interface{}, 1),
|
Inputs: make([]interface{}, 1),
|
||||||
PgType: m.Return[0].PgType,
|
PgType: m.Return[0].PgType,
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr := range p.contract.TknHolderAddrs {
|
// Depending on the type of the arg choose
|
||||||
for i := p.contract.StartingBlock; i <= p.contract.LastBlock; i++ {
|
// the correct argument set to iterate over
|
||||||
hashArgs := []common.Address{common.HexToAddress(addr)}
|
var args map[interface{}]bool
|
||||||
in := make([]interface{}, len(hashArgs))
|
switch m.Args[0].Type.T {
|
||||||
strIn := make([]interface{}, len(hashArgs))
|
case abi.FixedBytesTy, abi.BytesTy:
|
||||||
for i, s := range hashArgs {
|
args = p.contract.EmittedBytes
|
||||||
in[i] = s
|
case abi.HashTy:
|
||||||
strIn[i] = s.String()
|
args = p.contract.EmittedHashes
|
||||||
}
|
case abi.AddressTy:
|
||||||
|
args = p.contract.EmittedAddrs
|
||||||
|
}
|
||||||
|
if len(args) == 0 { // If we haven't collected any args by now we can't call the method
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
results := make([]types.Result, 0, len(args))
|
||||||
|
|
||||||
|
for arg := range args {
|
||||||
|
in := []interface{}{arg}
|
||||||
|
strIn := []interface{}{contract.StringifyArg(arg)}
|
||||||
|
|
||||||
|
var out interface{}
|
||||||
|
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, in, &out, bn)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("poller error calling 1 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
|
}
|
||||||
|
strOut, err := stringify(out)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Inputs = strIn
|
||||||
|
result.Output = strOut
|
||||||
|
results = append(results, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist results as batch
|
||||||
|
err := p.PersistResults(results, m, p.contract.Address, p.contract.Name)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("poller error persisting 1 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use token holder address to poll methods that take 2 address arguments (e.g. allowance)
|
||||||
|
func (p *poller) pollDoubleArgAt(m types.Method, bn int64) error {
|
||||||
|
result := types.Result{
|
||||||
|
Block: bn,
|
||||||
|
Method: m,
|
||||||
|
Inputs: make([]interface{}, 2),
|
||||||
|
PgType: m.Return[0].PgType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on the type of the args choose
|
||||||
|
// the correct argument sets to iterate over
|
||||||
|
var firstArgs map[interface{}]bool
|
||||||
|
switch m.Args[0].Type.T {
|
||||||
|
case abi.FixedBytesTy, abi.BytesTy:
|
||||||
|
firstArgs = p.contract.EmittedBytes
|
||||||
|
case abi.HashTy:
|
||||||
|
firstArgs = p.contract.EmittedHashes
|
||||||
|
case abi.AddressTy:
|
||||||
|
firstArgs = p.contract.EmittedAddrs
|
||||||
|
}
|
||||||
|
if len(firstArgs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var secondArgs map[interface{}]bool
|
||||||
|
switch m.Args[1].Type.T {
|
||||||
|
case abi.FixedBytesTy, abi.BytesTy:
|
||||||
|
secondArgs = p.contract.EmittedBytes
|
||||||
|
case abi.HashTy:
|
||||||
|
secondArgs = p.contract.EmittedHashes
|
||||||
|
case abi.AddressTy:
|
||||||
|
secondArgs = p.contract.EmittedAddrs
|
||||||
|
}
|
||||||
|
if len(secondArgs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]types.Result, 0, len(firstArgs)*len(secondArgs))
|
||||||
|
|
||||||
|
for arg1 := range firstArgs {
|
||||||
|
for arg2 := range secondArgs {
|
||||||
|
in := []interface{}{arg1, arg2}
|
||||||
|
strIn := []interface{}{contract.StringifyArg(arg1), contract.StringifyArg(arg2)}
|
||||||
|
|
||||||
var out interface{}
|
var out interface{}
|
||||||
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, in, &out, i)
|
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, in, &out, bn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("poller error calling 1 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
return errors.New(fmt.Sprintf("poller error calling 2 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
strOut, err := stringify(out)
|
strOut, err := stringify(out)
|
||||||
@ -140,61 +225,15 @@ func (p *poller) pollSingleArg(m types.Method) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.Output = strOut
|
result.Output = strOut
|
||||||
result.Block = i
|
|
||||||
result.Inputs = strIn
|
result.Inputs = strIn
|
||||||
|
results = append(results, result)
|
||||||
|
|
||||||
err = p.PersistResult(result, p.contract.Address, p.contract.Name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("poller error persisting 1 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
err := p.PersistResults(results, m, p.contract.Address, p.contract.Name)
|
||||||
}
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("poller error persisting 2 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", bn, m.Name, p.contract.Address, err))
|
||||||
// Use token holder address to poll methods that take 2 address arguments (e.g. allowance)
|
|
||||||
func (p *poller) pollDoubleArg(m types.Method) error {
|
|
||||||
// For a large block range and address list this will take a really, really long time- maybe we should only do 1 arg methods
|
|
||||||
result := types.Result{
|
|
||||||
Method: m,
|
|
||||||
Inputs: make([]interface{}, 2),
|
|
||||||
PgType: m.Return[0].PgType,
|
|
||||||
}
|
|
||||||
|
|
||||||
for addr1 := range p.contract.TknHolderAddrs {
|
|
||||||
for addr2 := range p.contract.TknHolderAddrs {
|
|
||||||
for i := p.contract.StartingBlock; i <= p.contract.LastBlock; i++ {
|
|
||||||
hashArgs := []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}
|
|
||||||
in := make([]interface{}, len(hashArgs))
|
|
||||||
strIn := make([]interface{}, len(hashArgs))
|
|
||||||
for i, s := range hashArgs {
|
|
||||||
in[i] = s
|
|
||||||
strIn[i] = s.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
var out interface{}
|
|
||||||
err := p.bc.FetchContractData(p.contract.Abi, p.contract.Address, m.Name, in, &out, i)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("poller error calling 2 argument method\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
strOut, err := stringify(out)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Output = strOut
|
|
||||||
result.Block = i
|
|
||||||
result.Inputs = strIn
|
|
||||||
|
|
||||||
err = p.PersistResult(result, p.contract.Address, p.contract.Name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("poller error persisting 2 argument method result\r\nblock: %d, method: %s, contract: %s\r\nerr: %v", i, m.Name, p.contract.Address, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -208,19 +247,22 @@ func (p *poller) FetchContractData(contractAbi, contractAddress, method string,
|
|||||||
func stringify(input interface{}) (string, error) {
|
func stringify(input interface{}) (string, error) {
|
||||||
switch input.(type) {
|
switch input.(type) {
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
var b *big.Int
|
b := input.(*big.Int)
|
||||||
b = input.(*big.Int)
|
|
||||||
return b.String(), nil
|
return b.String(), nil
|
||||||
case common.Address:
|
case common.Address:
|
||||||
var a common.Address
|
a := input.(common.Address)
|
||||||
a = input.(common.Address)
|
|
||||||
return a.String(), nil
|
return a.String(), nil
|
||||||
case common.Hash:
|
case common.Hash:
|
||||||
var h common.Hash
|
h := input.(common.Hash)
|
||||||
h = input.(common.Hash)
|
|
||||||
return h.String(), nil
|
return h.String(), nil
|
||||||
case string:
|
case string:
|
||||||
return input.(string), nil
|
return input.(string), nil
|
||||||
|
case []byte:
|
||||||
|
b := hexutil.Encode(input.([]byte))
|
||||||
|
return b, nil
|
||||||
|
case byte:
|
||||||
|
b := input.(byte)
|
||||||
|
return string(b), nil
|
||||||
case bool:
|
case bool:
|
||||||
return strconv.FormatBool(input.(bool)), nil
|
return strconv.FormatBool(input.(bool)), nil
|
||||||
default:
|
default:
|
||||||
|
@ -19,6 +19,7 @@ package poller_test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
@ -54,10 +55,7 @@ var _ = Describe("Poller", func() {
|
|||||||
Expect(con.Abi).To(Equal(constants.TusdAbiString))
|
Expect(con.Abi).To(Equal(constants.TusdAbiString))
|
||||||
con.StartingBlock = 6707322
|
con.StartingBlock = 6707322
|
||||||
con.LastBlock = 6707323
|
con.LastBlock = 6707323
|
||||||
con.TknHolderAddrs = map[string]bool{
|
con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE"))
|
||||||
"0xfE9e8709d3215310075d67E3ed32A380CCf451C8": true,
|
|
||||||
"0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := p.PollContract(*con)
|
err := p.PollContract(*con)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -90,10 +88,7 @@ var _ = Describe("Poller", func() {
|
|||||||
Expect(con.Abi).To(Equal(constants.TusdAbiString))
|
Expect(con.Abi).To(Equal(constants.TusdAbiString))
|
||||||
con.StartingBlock = 6707322
|
con.StartingBlock = 6707322
|
||||||
con.LastBlock = 6707323
|
con.LastBlock = 6707323
|
||||||
con.TknHolderAddrs = map[string]bool{
|
con.AddEmittedAddr(common.HexToAddress("0xfE9e8709d3215310075d67E3ed32A380CCf451C8"), common.HexToAddress("0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE"))
|
||||||
"0xfE9e8709d3215310075d67E3ed32A380CCf451C8": true,
|
|
||||||
"0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := p.PollContract(*con)
|
err := p.PollContract(*con)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
@ -19,12 +19,12 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/light/repository"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/omni/light/repository"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,12 +65,8 @@ func NewEventRepository(db *postgres.DB, mode types.Mode) *eventRepository {
|
|||||||
// Creates table for the watched contract event if needed
|
// Creates table for the watched contract event if needed
|
||||||
// Persists converted event log data into this custom table
|
// Persists converted event log data into this custom table
|
||||||
func (r *eventRepository) PersistLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
func (r *eventRepository) PersistLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
||||||
if logs == nil {
|
|
||||||
return errors.New("event repository error: passed a nil log slice")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(logs) == 0 {
|
if len(logs) == 0 {
|
||||||
return errors.New("event repository error: passed an empty log slice")
|
return errors.New("event repository error: passed empty logs slice")
|
||||||
}
|
}
|
||||||
_, err := r.CreateContractSchema(contractAddr)
|
_, err := r.CreateContractSchema(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,7 +108,7 @@ func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types
|
|||||||
pgStr = pgStr + "(header_id, token_name, raw_log, log_idx, tx_idx"
|
pgStr = pgStr + "(header_id, token_name, raw_log, log_idx, tx_idx"
|
||||||
el := len(event.Values)
|
el := len(event.Values)
|
||||||
|
|
||||||
// Pack the corresponding variables in a slice
|
// Preallocate slice of needed capacity and proceed to pack variables into it in same order they appear in string
|
||||||
data := make([]interface{}, 0, 5+el)
|
data := make([]interface{}, 0, 5+el)
|
||||||
data = append(data,
|
data = append(data,
|
||||||
event.Id,
|
event.Id,
|
||||||
@ -134,6 +130,7 @@ func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types
|
|||||||
}
|
}
|
||||||
pgStr = pgStr + ")"
|
pgStr = pgStr + ")"
|
||||||
|
|
||||||
|
// Add this query to the transaction
|
||||||
_, err = tx.Exec(pgStr, data...)
|
_, err = tx.Exec(pgStr, data...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
@ -141,8 +138,9 @@ func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark header as checked for this eventId
|
||||||
eventId := strings.ToLower(eventInfo.Name + "_" + contractAddr)
|
eventId := strings.ToLower(eventInfo.Name + "_" + contractAddr)
|
||||||
err = repository.MarkHeaderCheckedInTransaction(logs[0].Id, tx, eventId)
|
err = repository.MarkHeaderCheckedInTransaction(logs[0].Id, tx, eventId) // This assumes all logs are from same block
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
geth "github.com/ethereum/go-ethereum/core/types"
|
geth "github.com/ethereum/go-ethereum/core/types"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -137,15 +138,15 @@ var _ = Describe("Repository", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Persists contract event log values into custom tables, adding any addresses to a growing list of contract associated addresses", func() {
|
It("Persists contract event log values into custom tables", func() {
|
||||||
err = dataStore.PersistLogs([]types.Log{*log}, event, con.Address, con.Name)
|
err = dataStore.PersistLogs([]types.Log{*log}, event, con.Address, con.Name)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
b, ok := con.TknHolderAddrs["0x000000000000000000000000000000000000Af21"]
|
b, ok := con.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
b, ok = con.TknHolderAddrs["0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"]
|
b, ok = con.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391")]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
Expect(b).To(Equal(true))
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ import (
|
|||||||
const methodCacheSize = 1000
|
const methodCacheSize = 1000
|
||||||
|
|
||||||
type MethodRepository interface {
|
type MethodRepository interface {
|
||||||
PersistResult(method types.Result, contractAddr, contractName string) error
|
PersistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error
|
||||||
CreateMethodTable(contractAddr string, method types.Result) (bool, error)
|
CreateMethodTable(contractAddr string, method types.Method) (bool, error)
|
||||||
CreateContractSchema(contractAddr string) (bool, error)
|
CreateContractSchema(contractAddr string) (bool, error)
|
||||||
CheckSchemaCache(key string) (interface{}, bool)
|
CheckSchemaCache(key string) (interface{}, bool)
|
||||||
CheckTableCache(key string) (interface{}, bool)
|
CheckTableCache(key string) (interface{}, bool)
|
||||||
@ -55,65 +55,74 @@ func NewMethodRepository(db *postgres.DB, mode types.Mode) *methodRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *methodRepository) PersistResult(method types.Result, contractAddr, contractName string) error {
|
// Creates a schema for the contract if needed
|
||||||
if len(method.Args) != len(method.Inputs) {
|
// Creates table for the contract method if needed
|
||||||
return errors.New("error: given number of inputs does not match number of method arguments")
|
// Persists method polling data into this custom table
|
||||||
|
func (r *methodRepository) PersistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error {
|
||||||
|
if len(results) == 0 {
|
||||||
|
return errors.New("method repository error: passed empty results slice")
|
||||||
}
|
}
|
||||||
if len(method.Return) != 1 {
|
|
||||||
return errors.New("error: given number of outputs does not match number of method return values")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := r.CreateContractSchema(contractAddr)
|
_, err := r.CreateContractSchema(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.CreateMethodTable(contractAddr, method)
|
_, err = r.CreateMethodTable(contractAddr, methodInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.persistResult(method, contractAddr, contractName)
|
return r.persistResults(results, methodInfo, contractAddr, contractName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a custom postgres command to persist logs for the given event
|
// Creates a custom postgres command to persist logs for the given event
|
||||||
func (r *methodRepository) persistResult(method types.Result, contractAddr, contractName string) error {
|
func (r *methodRepository) persistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error {
|
||||||
// Begin postgres string
|
tx, err := r.DB.Begin()
|
||||||
pgStr := fmt.Sprintf("INSERT INTO %s_%s.%s_method ", r.mode.String(), strings.ToLower(contractAddr), strings.ToLower(method.Name))
|
|
||||||
pgStr = pgStr + "(token_name, block"
|
|
||||||
ml := len(method.Args)
|
|
||||||
|
|
||||||
// Preallocate slice of needed size and proceed to pack variables into it in same order they appear in string
|
|
||||||
data := make([]interface{}, 0, 3+ml)
|
|
||||||
data = append(data,
|
|
||||||
contractName,
|
|
||||||
method.Block)
|
|
||||||
|
|
||||||
// Iterate over method args and return value, adding names
|
|
||||||
// to the string and pushing values to the slice
|
|
||||||
for i, arg := range method.Args {
|
|
||||||
pgStr = pgStr + fmt.Sprintf(", %s_", strings.ToLower(arg.Name)) // Add underscore after to avoid any collisions with reserved pg words
|
|
||||||
data = append(data, method.Inputs[i])
|
|
||||||
}
|
|
||||||
pgStr = pgStr + ", returned) VALUES ($1, $2"
|
|
||||||
data = append(data, method.Output)
|
|
||||||
|
|
||||||
// For each input entry we created we add its postgres command variable to the string
|
|
||||||
for i := 0; i <= ml; i++ {
|
|
||||||
pgStr = pgStr + fmt.Sprintf(", $%d", i+3)
|
|
||||||
}
|
|
||||||
pgStr = pgStr + ")"
|
|
||||||
|
|
||||||
_, err := r.DB.Exec(pgStr, data...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
for _, result := range results {
|
||||||
|
// Begin postgres string
|
||||||
|
pgStr := fmt.Sprintf("INSERT INTO %s_%s.%s_method ", r.mode.String(), strings.ToLower(contractAddr), strings.ToLower(result.Name))
|
||||||
|
pgStr = pgStr + "(token_name, block"
|
||||||
|
ml := len(result.Args)
|
||||||
|
|
||||||
|
// Preallocate slice of needed capacity and proceed to pack variables into it in same order they appear in string
|
||||||
|
data := make([]interface{}, 0, 3+ml)
|
||||||
|
data = append(data,
|
||||||
|
contractName,
|
||||||
|
result.Block)
|
||||||
|
|
||||||
|
// Iterate over method args and return value, adding names
|
||||||
|
// to the string and pushing values to the slice
|
||||||
|
for i, arg := range result.Args {
|
||||||
|
pgStr = pgStr + fmt.Sprintf(", %s_", strings.ToLower(arg.Name)) // Add underscore after to avoid any collisions with reserved pg words
|
||||||
|
data = append(data, result.Inputs[i])
|
||||||
|
}
|
||||||
|
pgStr = pgStr + ", returned) VALUES ($1, $2"
|
||||||
|
data = append(data, result.Output)
|
||||||
|
|
||||||
|
// For each input entry we created we add its postgres command variable to the string
|
||||||
|
for i := 0; i <= ml; i++ {
|
||||||
|
pgStr = pgStr + fmt.Sprintf(", $%d", i+3)
|
||||||
|
}
|
||||||
|
pgStr = pgStr + ")"
|
||||||
|
|
||||||
|
// Add this query to the transaction
|
||||||
|
_, err = tx.Exec(pgStr, data...)
|
||||||
|
if err != nil {
|
||||||
|
println("howdy")
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for event table and creates it if it does not already exist
|
// Checks for event table and creates it if it does not already exist
|
||||||
func (r *methodRepository) CreateMethodTable(contractAddr string, method types.Result) (bool, error) {
|
func (r *methodRepository) CreateMethodTable(contractAddr string, method types.Method) (bool, error) {
|
||||||
tableID := fmt.Sprintf("%s_%s.%s_method", r.mode.String(), strings.ToLower(contractAddr), strings.ToLower(method.Name))
|
tableID := fmt.Sprintf("%s_%s.%s_method", r.mode.String(), strings.ToLower(contractAddr), strings.ToLower(method.Name))
|
||||||
|
|
||||||
// Check cache before querying pq to see if table exists
|
// Check cache before querying pq to see if table exists
|
||||||
@ -139,7 +148,7 @@ func (r *methodRepository) CreateMethodTable(contractAddr string, method types.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a table for the given contract and event
|
// Creates a table for the given contract and event
|
||||||
func (r *methodRepository) newMethodTable(tableID string, method types.Result) error {
|
func (r *methodRepository) newMethodTable(tableID string, method types.Method) error {
|
||||||
// Begin pg string
|
// Begin pg string
|
||||||
pgStr := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s ", tableID)
|
pgStr := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s ", tableID)
|
||||||
pgStr = pgStr + "(id SERIAL, token_name CHARACTER VARYING(66) NOT NULL, block INTEGER NOT NULL,"
|
pgStr = pgStr + "(id SERIAL, token_name CHARACTER VARYING(66) NOT NULL, block INTEGER NOT NULL,"
|
||||||
|
@ -95,11 +95,11 @@ var _ = Describe("Repository", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, mockResult)
|
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, mockResult)
|
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(false))
|
Expect(created).To(Equal(false))
|
||||||
})
|
})
|
||||||
@ -113,7 +113,7 @@ var _ = Describe("Repository", func() {
|
|||||||
_, ok := dataStore.CheckTableCache(tableID)
|
_, ok := dataStore.CheckTableCache(tableID)
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(con.Address, mockResult)
|
created, err = dataStore.CreateMethodTable(con.Address, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ var _ = Describe("Repository", func() {
|
|||||||
|
|
||||||
Describe("PersistResult", func() {
|
Describe("PersistResult", func() {
|
||||||
It("Persists result from method polling in custom pg table", func() {
|
It("Persists result from method polling in custom pg table", func() {
|
||||||
err = dataStore.PersistResult(mockResult, con.Address, con.Name)
|
err = dataStore.PersistResults([]types.Result{mockResult}, method, con.Address, con.Name)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
scanStruct := test_helpers.BalanceOf{}
|
scanStruct := test_helpers.BalanceOf{}
|
||||||
@ -142,7 +142,7 @@ var _ = Describe("Repository", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Fails with empty result", func() {
|
It("Fails with empty result", func() {
|
||||||
err = dataStore.PersistResult(types.Result{}, con.Address, con.Name)
|
err = dataStore.PersistResults([]types.Result{}, method, con.Address, con.Name)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -184,11 +184,11 @@ var _ = Describe("Repository", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, mockResult)
|
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, mockResult)
|
created, err = dataStore.CreateMethodTable(constants.TusdContractAddress, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(false))
|
Expect(created).To(Equal(false))
|
||||||
})
|
})
|
||||||
@ -202,7 +202,7 @@ var _ = Describe("Repository", func() {
|
|||||||
_, ok := dataStore.CheckTableCache(tableID)
|
_, ok := dataStore.CheckTableCache(tableID)
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
created, err = dataStore.CreateMethodTable(con.Address, mockResult)
|
created, err = dataStore.CreateMethodTable(con.Address, method)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(created).To(Equal(true))
|
Expect(created).To(Equal(true))
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ var _ = Describe("Repository", func() {
|
|||||||
|
|
||||||
Describe("PersistResult", func() {
|
Describe("PersistResult", func() {
|
||||||
It("Persists result from method polling in custom pg table for light sync mode vDB", func() {
|
It("Persists result from method polling in custom pg table for light sync mode vDB", func() {
|
||||||
err = dataStore.PersistResult(mockResult, con.Address, con.Name)
|
err = dataStore.PersistResults([]types.Result{mockResult}, method, con.Address, con.Name)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
scanStruct := test_helpers.BalanceOf{}
|
scanStruct := test_helpers.BalanceOf{}
|
||||||
@ -231,7 +231,7 @@ var _ = Describe("Repository", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Fails with empty result", func() {
|
It("Fails with empty result", func() {
|
||||||
err = dataStore.PersistResult(types.Result{}, con.Address, con.Name)
|
err = dataStore.PersistResults([]types.Result{}, method, con.Address, con.Name)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -59,7 +59,7 @@ func NewEvent(e abi.Event) Event {
|
|||||||
fields[i].Indexed = input.Indexed
|
fields[i].Indexed = input.Indexed
|
||||||
// Fill in pg type based on abi type
|
// Fill in pg type based on abi type
|
||||||
switch fields[i].Type.T {
|
switch fields[i].Type.T {
|
||||||
case abi.StringTy, abi.HashTy, abi.AddressTy:
|
case abi.HashTy, abi.AddressTy:
|
||||||
fields[i].PgType = "CHARACTER VARYING(66)"
|
fields[i].PgType = "CHARACTER VARYING(66)"
|
||||||
case abi.IntTy, abi.UintTy:
|
case abi.IntTy, abi.UintTy:
|
||||||
fields[i].PgType = "DECIMAL"
|
fields[i].PgType = "DECIMAL"
|
||||||
@ -71,8 +71,6 @@ func NewEvent(e abi.Event) Event {
|
|||||||
fields[i].PgType = "TEXT[]"
|
fields[i].PgType = "TEXT[]"
|
||||||
case abi.FixedPointTy:
|
case abi.FixedPointTy:
|
||||||
fields[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
fields[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
||||||
case abi.FunctionTy:
|
|
||||||
fields[i].PgType = "TEXT"
|
|
||||||
default:
|
default:
|
||||||
fields[i].PgType = "TEXT"
|
fields[i].PgType = "TEXT"
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func NewMethod(m abi.Method) Method {
|
|||||||
inputs[i].Type = input.Type
|
inputs[i].Type = input.Type
|
||||||
inputs[i].Indexed = input.Indexed
|
inputs[i].Indexed = input.Indexed
|
||||||
switch inputs[i].Type.T {
|
switch inputs[i].Type.T {
|
||||||
case abi.StringTy, abi.HashTy, abi.AddressTy:
|
case abi.HashTy, abi.AddressTy:
|
||||||
inputs[i].PgType = "CHARACTER VARYING(66)"
|
inputs[i].PgType = "CHARACTER VARYING(66)"
|
||||||
case abi.IntTy, abi.UintTy:
|
case abi.IntTy, abi.UintTy:
|
||||||
inputs[i].PgType = "DECIMAL"
|
inputs[i].PgType = "DECIMAL"
|
||||||
@ -60,8 +60,6 @@ func NewMethod(m abi.Method) Method {
|
|||||||
inputs[i].PgType = "TEXT[]"
|
inputs[i].PgType = "TEXT[]"
|
||||||
case abi.FixedPointTy:
|
case abi.FixedPointTy:
|
||||||
inputs[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
inputs[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
||||||
case abi.FunctionTy:
|
|
||||||
inputs[i].PgType = "TEXT"
|
|
||||||
default:
|
default:
|
||||||
inputs[i].PgType = "TEXT"
|
inputs[i].PgType = "TEXT"
|
||||||
}
|
}
|
||||||
@ -74,7 +72,7 @@ func NewMethod(m abi.Method) Method {
|
|||||||
outputs[i].Type = output.Type
|
outputs[i].Type = output.Type
|
||||||
outputs[i].Indexed = output.Indexed
|
outputs[i].Indexed = output.Indexed
|
||||||
switch outputs[i].Type.T {
|
switch outputs[i].Type.T {
|
||||||
case abi.StringTy, abi.HashTy, abi.AddressTy:
|
case abi.HashTy, abi.AddressTy:
|
||||||
outputs[i].PgType = "CHARACTER VARYING(66)"
|
outputs[i].PgType = "CHARACTER VARYING(66)"
|
||||||
case abi.IntTy, abi.UintTy:
|
case abi.IntTy, abi.UintTy:
|
||||||
outputs[i].PgType = "DECIMAL"
|
outputs[i].PgType = "DECIMAL"
|
||||||
@ -86,8 +84,6 @@ func NewMethod(m abi.Method) Method {
|
|||||||
outputs[i].PgType = "TEXT[]"
|
outputs[i].PgType = "TEXT[]"
|
||||||
case abi.FixedPointTy:
|
case abi.FixedPointTy:
|
||||||
outputs[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
outputs[i].PgType = "MONEY" // use shopspring/decimal for fixed point numbers in go and money type in postgres?
|
||||||
case abi.FunctionTy:
|
|
||||||
outputs[i].PgType = "TEXT"
|
|
||||||
default:
|
default:
|
||||||
outputs[i].PgType = "TEXT"
|
outputs[i].PgType = "TEXT"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user