Process ENS records

This commit is contained in:
Martin Boehm 2022-04-16 01:33:22 +02:00 committed by Martin
parent 6fdf6e297c
commit 77561e3567
5 changed files with 135 additions and 13 deletions

View File

@ -21,6 +21,8 @@ const tokenTransferEventSignature = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f16
const tokenERC1155TransferSingleEventSignature = "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"
const tokenERC1155TransferBatchEventSignature = "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"
const nameRegisteredEventSignature = "0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f"
const contractNameSignature = "0x06fdde03"
const contractSymbolSignature = "0x95d89b41"
const contractDecimalsSignature = "0x313ce567"

View File

@ -163,16 +163,16 @@ func processParam(data string, index int, t *abi.Type, processed []bool) ([]stri
}
// get element count of dynamic type
c, err := strconv.ParseInt(data[d:d+64], 16, 64)
count := int(c)
if err != nil {
return nil, 0, false
}
count := int(c)
processed[dynIndex] = true
dynIndex++
if t.T == abi.StringTy || t.T == abi.BytesTy {
d += 64
de := d + (count << 1)
if de > len(data) {
if de > len(data) || de < 0 {
return nil, 0, false
}
if count == 0 {
@ -292,3 +292,27 @@ func ParseInputData(signatures *[]bchain.FourByteSignature, data string) *bchain
}
return &parsed
}
// getEnsRecord processes transaction log entry and tries to parse ENS record from it
func getEnsRecord(l *rpcLogWithTxHash) *bchain.AddressAliasRecord {
if len(l.Topics) == 3 && l.Topics[0] == nameRegisteredEventSignature && len(l.Data) >= 322 {
address, err := addressFromPaddedHex(l.Topics[2])
if err != nil {
return nil
}
c, err := strconv.ParseInt(l.Data[194:194+64], 16, 64)
if err != nil {
return nil
}
de := 194 + 64 + (int(c) << 1)
if de > len(l.Data) || de < 0 {
return nil
}
b, err := hex.DecodeString(l.Data[194+64 : de])
if err != nil {
return nil
}
return &bchain.AddressAliasRecord{Address: address, Name: string(b)}
}
return nil
}

View File

@ -367,3 +367,79 @@ func TestParseInputData(t *testing.T) {
})
}
}
func Test_getEnsRecord(t *testing.T) {
tests := []struct {
name string
log rpcLogWithTxHash
want *bchain.AddressAliasRecord
}{
{
name: "unraveled",
log: rpcLogWithTxHash{
RpcLog: bchain.RpcLog{
Address: "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5",
Topics: []string{
"0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f",
"0x40ce2aa8cd9ee9fef4bf3a68abab7fbcceb6bac89370518caf6a602cefe836bd",
"0x0000000000000000000000002c630b16aa53ae0189880e15c23323688acb607c",
},
Data: "0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000017629245f5a86f0000000000000000000000000000000000000000000000000000000069dbb21d0000000000000000000000000000000000000000000000000000000000000009756e726176656c65640000000000000000000000000000000000000000000000",
},
},
want: &bchain.AddressAliasRecord{Address: "0x2C630b16Aa53ae0189880e15C23323688acb607c", Name: "unraveled"},
},
{
name: "4x unraveled",
log: rpcLogWithTxHash{
RpcLog: bchain.RpcLog{
Address: "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5",
Topics: []string{
"0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f",
"0x40ce2aa8cd9ee9fef4bf3a68abab7fbcceb6bac89370518caf6a602cefe836bd",
"0x0000000000000000000000002c630b16aa53ae0189880e15c23323688acb607c",
},
Data: "0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000017629245f5a86f0000000000000000000000000000000000000000000000000000000069dbb21d0000000000000000000000000000000000000000000000000000000000000024756e726176656c6564756e726176656c6564756e726176656c6564756e726176656c656400000000000000000000000000000000000000000000000000000000",
},
},
want: &bchain.AddressAliasRecord{Address: "0x2C630b16Aa53ae0189880e15C23323688acb607c", Name: "unraveledunraveledunraveledunraveled"},
},
{
name: "no signature",
log: rpcLogWithTxHash{
RpcLog: bchain.RpcLog{
Address: "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5",
Topics: []string{
"0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404e",
"0x40ce2aa8cd9ee9fef4bf3a68abab7fbcceb6bac89370518caf6a602cefe836bd",
"0x0000000000000000000000002c630b16aa53ae0189880e15c23323688acb607c",
},
Data: "0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000017629245f5a86f0000000000000000000000000000000000000000000000000000000069dbb21d0000000000000000000000000000000000000000000000000000000000000009756e726176656c65640000000000000000000000000000000000000000000000",
},
},
want: nil,
},
{
name: "name length does not match",
log: rpcLogWithTxHash{
RpcLog: bchain.RpcLog{
Address: "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5",
Topics: []string{
"0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f",
"0x40ce2aa8cd9ee9fef4bf3a68abab7fbcceb6bac89370518caf6a602cefe836bd",
"0x0000000000000000000000002c630b16aa53ae0189880e15c23323688acb607c",
},
Data: "0x00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000017629245f5a86f0000000000000000000000000000000000000000000000000000000069dbb21d0000000000000000000000000000000000000000000000000000000000000ff9756e726176656c65640000000000000000000000000000000000000000000000",
},
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getEnsRecord(&tt.log); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getEnsRecord() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -497,24 +497,28 @@ func (b *EthereumRPC) getBlockRaw(hash string, height uint32, fullTxs bool) (jso
return raw, nil
}
func (b *EthereumRPC) getTokenTransferEventsForBlock(blockNumber string) (map[string][]*bchain.RpcLog, error) {
func (b *EthereumRPC) processEventsForBlock(blockNumber string) (map[string][]*bchain.RpcLog, []bchain.AddressAliasRecord, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
var logs []rpcLogWithTxHash
var ensRecords []bchain.AddressAliasRecord
err := b.rpc.CallContext(ctx, &logs, "eth_getLogs", map[string]interface{}{
"fromBlock": blockNumber,
"toBlock": blockNumber,
// "topics": []string{tokenTransferEventSignature, tokenERC1155TransferSingleEventSignature, tokenERC1155TransferBatchEventSignature},
})
if err != nil {
return nil, errors.Annotatef(err, "blockNumber %v", blockNumber)
return nil, nil, errors.Annotatef(err, "blockNumber %v", blockNumber)
}
r := make(map[string][]*bchain.RpcLog)
for i := range logs {
l := &logs[i]
r[l.Hash] = append(r[l.Hash], &l.RpcLog)
ens := getEnsRecord(l)
if ens != nil {
ensRecords = append(ensRecords, *ens)
}
}
return r, nil
return r, ensRecords, nil
}
type rpcCallTrace struct {
@ -636,17 +640,24 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
if err != nil {
return nil, errors.Annotatef(err, "hash %v, height %v", hash, height)
}
// get contract transfers events
logs, err := b.getTokenTransferEventsForBlock(head.Number)
// get block events
logs, ens, err := b.processEventsForBlock(head.Number)
if err != nil {
return nil, err
}
// error fetching internal data does not stop the block processing
var blockSpecificData *bchain.EthereumBlockSpecificData
internalData, err := b.getInternalDataForBlock(head.Hash, body.Transactions)
if err != nil {
blockSpecificData = &bchain.EthereumBlockSpecificData{InternalDataError: err.Error()}
glog.Info("InternalDataError ", bbh.Height, ": ", err.Error())
if err != nil || len(ens) > 0 {
blockSpecificData = &bchain.EthereumBlockSpecificData{}
if err != nil {
blockSpecificData.InternalDataError = err.Error()
glog.Info("InternalDataError ", bbh.Height, ": ", err.Error())
}
if len(ens) > 0 {
blockSpecificData.AddressAliasRecords = ens
glog.Info("ENS", ens)
}
}
btxs := make([]bchain.Tx, len(body.Transactions))

View File

@ -121,12 +121,21 @@ type RpcReceipt struct {
Logs []*RpcLog `json:"logs"`
}
// EthereumSpecificData contains data specific to Ethereum transactions
type EthereumSpecificData struct {
Tx *RpcTransaction `json:"tx"`
InternalData *EthereumInternalData `json:"internalData,omitempty"`
Receipt *RpcReceipt `json:"receipt,omitempty"`
}
type EthereumBlockSpecificData struct {
InternalDataError string
// AddressAliasRecord maps address to ENS name
type AddressAliasRecord struct {
Address string
Name string
}
// EthereumBlockSpecificData contain data specific for Ethereum block
type EthereumBlockSpecificData struct {
InternalDataError string
AddressAliasRecords []AddressAliasRecord
}