pragmasolidity^0.5.0;import"../ResolverBase.sol";contractGeoENSResolverisResolverBase{bytes4constantERC2390=0x8fbcc5ce;uintconstantMAX_ADDR_RETURNS=64;uintconstantTREE_VISITATION_QUEUESZ=64;uint8constantASCII_0=48;uint8constantASCII_9=57;uint8constantASCII_a=97;uint8constantASCII_b=98;uint8constantASCII_i=105;uint8constantASCII_l=108;uint8constantASCII_o=111;uint8constantASCII_z=122;structNode{addressdata;// 0 if not leaf
uint256parent;uint256[]children;// always length 32
}// A geohash is 8, base-32 characters.
// A geomap is stored as tree of fan-out 32 (because
// geohash is base 32) and height 8 (because geohash
// length is 8 characters)
// geohash 为 8 个 base-32 字符。
// geomap 存储为扇出为 32 的树(因为
// geohash 为 base 32)和高度为 8(因为 geohash
// 长度为 8 个字符)
mapping(bytes32=>Node[])privategeomap;eventGeoENSRecordChanged(bytes32indexednode,bytes8geohash,addressaddr);// only 5 bits of ret value are used
// 仅使用 ret 值的 5 位
functionchartobase32(bytec)pureinternalreturns(uint8b){uint8ascii=uint8(c);require((ascii>=ASCII_0&&ascii<=ASCII_9)||(ascii>ASCII_a&&ascii<=ASCII_z));require(ascii!=ASCII_a);require(ascii!=ASCII_i);require(ascii!=ASCII_l);require(ascii!=ASCII_o);if(ascii<=(ASCII_0+9)){b=ascii-ASCII_0;}else{// base32 b = 10
// ascii 'b' = 0x60
// note base32 skips the letter 'a'
// base32 b = 10
// ascii 'b' = 0x60
// 注意 base32 跳过字母 'a'
b=ascii-ASCII_b+10;// base32 also skips the following letters
// base32 也跳过以下字母
if(ascii>ASCII_i)b--;if(ascii>ASCII_l)b--;if(ascii>ASCII_o)b--;}require(b<32);// base 32 can't be larger than 32
returnb;}functiongeoAddr(bytes32node,bytes8geohash,uint8precision)externalviewreturns(address[]memoryret){bytes32(node);// single node georesolver ignores node
assert(precision<=geohash.length);ret=newaddress[](MAX_ADDR_RETURNS);if(geomap[node].length==0){returnret;}uintret_i=0;// walk into the geomap data structure
// 走进 geomap 数据结构
uintpointer=0;// not actual pointer but index into geomap
for(uint8i=0;i<precision;i++){uint8c=chartobase32(geohash[i]);uintnext=geomap[node][pointer].children[c];if(next==0){// nothing found for this geohash.
// return early.
// 没有找到此 geohash 的任何内容。
// 提前返回。
returnret;}else{pointer=next;}}// pointer is now node representing the resolution of the query geohash.
// DFS until all addresses found or ret[] is full.
// Do not use recursion because blockchain...
// 指针现在是表示查询 geohash 的解析的节点。
// DFS 直到找到所有地址或 ret[] 已满。
// 不要使用递归,因为区块链...
uint[]memoryindexes_to_visit=newuint[](TREE_VISITATION_QUEUESZ);indexes_to_visit[0]=pointer;uintfront_i=0;uintback_i=1;while(front_i!=back_i){Nodememorycur_node=geomap[node][indexes_to_visit[front_i]];front_i++;// if not a leaf node...
// 如果不是叶节点...
if(cur_node.data==address(0)){// visit all the chilins
// 访问所有孩子
for(uinti=0;i<cur_node.children.length;i++){// only visit valid children
// 仅访问有效的孩子
if(cur_node.children[i]!=0){assert(back_i<TREE_VISITATION_QUEUESZ);indexes_to_visit[back_i]=cur_node.children[i];back_i++;}}}else{ret[ret_i]=cur_node.data;ret_i++;if(ret_i>MAX_ADDR_RETURNS)break;}}returnret;}// when setting, geohash must be precise to 8 digits.
// 设置时,geohash 必须精确到 8 位数字。
functionsetGeoAddr(bytes32node,bytes8geohash,addressaddr)externalauthorised(node){bytes32(node);// single node georesolver ignores node
// create root node if not yet created
// 如果尚未创建,则创建根节点
if(geomap[node].length==0){geomap[node].push(Node({data:address(0),parent:0,children:newuint256[](32)}));}// walk into the geomap data structure
// 走进 geomap 数据结构
uintpointer=0;// not actual pointer but index into geomap
for(uinti=0;i<geohash.length;i++){uint8c=chartobase32(geohash[i]);if(geomap[node][pointer].children[c]==0){// nothing found for this geohash.
// we need to create a path to the leaf
// 没有找到此 geohash 的任何内容。
// 我们需要创建到叶子的路径
geomap[node].push(Node({data:address(0),parent:pointer,children:newuint256[](32)}));geomap[node][pointer].children[c]=geomap[node].length-1;}pointer=geomap[node][pointer].children[c];}Nodestoragecur_node=geomap[node][pointer];// storage = get reference
cur_node.data=addr;emitGeoENSRecordChanged(node,geohash,addr);}functionsupportsInterface(bytes4interfaceID)publicpurereturns(bool){returninterfaceID==ERC2390||super.supportsInterface(interfaceID);}}